mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-14 19:44:04 +02:00
b6ef8792f8
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@2781 3c298f89-4303-0410-b956-a3cf2f4a3e73
4891 lines
160 KiB
Diff
4891 lines
160 KiB
Diff
diff -urN linux-2.4.32.new/arch/mips/ar531x/ae531xlnx.c linux-2.4.32.new-eth/arch/mips/ar531x/ae531xlnx.c
|
||
--- linux-2.4.32.new/arch/mips/ar531x/ae531xlnx.c 1970-01-01 01:00:00.000000000 +0100
|
||
+++ linux-2.4.32.new-eth/arch/mips/ar531x/ae531xlnx.c 2005-12-25 11:54:20.756273952 +0000
|
||
@@ -0,0 +1,1534 @@
|
||
+/*
|
||
+ * This file is subject to the terms and conditions of the GNU General Public
|
||
+ * License. See the file "COPYING" in the main directory of this archive
|
||
+ * for more details.
|
||
+ *
|
||
+ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
|
||
+ */
|
||
+
|
||
+/*
|
||
+ * Ethernet driver for Atheros' ae531x ethernet MAC.
|
||
+ * This is a fairly generic driver, but it's intended
|
||
+ * for use in typical Atheros products.
|
||
+ */
|
||
+
|
||
+#include <linux/config.h>
|
||
+#include <linux/types.h>
|
||
+#include <linux/delay.h>
|
||
+#include <linux/netdevice.h>
|
||
+#include <linux/etherdevice.h>
|
||
+#include <linux/init.h>
|
||
+#include <linux/skbuff.h>
|
||
+#include <asm/io.h>
|
||
+
|
||
+#include "ar531xlnx.h"
|
||
+#include "ae531xreg.h"
|
||
+#include "ae531xmac.h"
|
||
+
|
||
+/*
|
||
+ * A word about CONFIG_VENETDEV: It's intended to support two
|
||
+ * "virtualized ethernet devices" that share a single underlying MAC.
|
||
+ * To upper layers, it appears that the hardware supports two MACs,
|
||
+ * with enet0 used for LAN ports and enet1 used for a WAN port. This
|
||
+ * is useful, for instance, when building a 5-port router on hardware
|
||
+ * that uses only one of the AR5312's ethernet MACs.
|
||
+ *
|
||
+ * Virtualization is accomplished through trickery at the ethernet
|
||
+ * PHY layer. We use PHY hardware to determine which port a packet
|
||
+ * was received on, and in order to direct a packet to a particular
|
||
+ * port or set of ports.
|
||
+ *
|
||
+ * The code is mostly written to be generalized to more than two
|
||
+ * virtual devices; but it's intended for one multi-port LAN enet
|
||
+ * device and one single-port WAN enet device.
|
||
+ */
|
||
+
|
||
+#define AE531X_LAN_PORT 0
|
||
+#ifdef CONFIG_VENETDEV
|
||
+#define AE531X_DEV_PER_MAC 2
|
||
+#define AE531X_WAN_PORT 1
|
||
+#else
|
||
+#define AE531X_DEV_PER_MAC 1
|
||
+#endif
|
||
+
|
||
+
|
||
+/*
|
||
+ * ae531x_MAC_state contains driver-specific linux-specific per-MAC information.
|
||
+ * The OSinfo member of ae531x_MAC_t points to one of these.
|
||
+ */
|
||
+typedef struct ae531x_MAC_state {
|
||
+ int irq;
|
||
+ struct tq_struct restart_task;
|
||
+ struct net_device_stats stats;
|
||
+ struct ae531x_dev_sw_state *dev_sw_state[AE531X_DEV_PER_MAC];
|
||
+ int primary_dev;
|
||
+ ae531x_MAC_t MACInfo; /* hardware state */
|
||
+} ae531x_MAC_state_t;
|
||
+
|
||
+/*
|
||
+ * ae531x_dev_sw_state contains driver-specific linux-specific per-device
|
||
+ * information. The net_device priv member points to one of these, and
|
||
+ * this structure contains a pointer to the associated MAC information.
|
||
+ * In the case of CONFIG_VENETDEV, each virtual device has its own
|
||
+ * ae531x_dev_sw_state, and virtual devices that share a physical MAC
|
||
+ * point to the same ae531x_MAC_state.
|
||
+ */
|
||
+typedef struct ae531x_dev_sw_state {
|
||
+ int enetUnit; /* system unit number "eth%d" */
|
||
+ int unit_on_MAC; /* MAC-relative unit number */
|
||
+ struct net_device *dev;
|
||
+ ae531x_MAC_state_t *MAC_state; /* underlying MAC hw/sw state */
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ BOOL isLAN; /* 0-->WAN; 1-->LAN */
|
||
+#endif
|
||
+} ae531x_dev_sw_state_t;
|
||
+
|
||
+/*
|
||
+ * Driver-independent linux-specific per-ethernet device software information.
|
||
+ * Regarding CONFIG_VENETDEV: If a system has 2 physical MACs, and each
|
||
+ * physical MAC has 2 virtual ethernet devices (one for LAN and one for WAN),
|
||
+ * then there are a total of 4 ethernet devices.
|
||
+ */
|
||
+static struct net_device *ae531x_MAC_dev[AR531X_NUM_ENET_MAC * AE531X_DEV_PER_MAC];
|
||
+
|
||
+/* Driver-dependent per-MAC information */
|
||
+static ae531x_MAC_state_t per_MAC_info[AR531X_NUM_ENET_MAC];
|
||
+
|
||
+/*
|
||
+ * Receive buffers need enough room to hold the following:
|
||
+ * 1) a max MTU-sized packet.
|
||
+ * 2) space for an ethernet header
|
||
+ * 3) room at the beginning of the receive buffer in order
|
||
+ * to facilitate cooperating drivers that need to PREpend
|
||
+ * data.
|
||
+ * 4) Depending on configuration, we may need some additional
|
||
+ * room at the END of the rx buffer for phy-supplied
|
||
+ * trailers (if any). (c.f. CONFIG_VENETDEV)
|
||
+ *
|
||
+ * The DMA engine insists on 32-bit aligned RX buffers.
|
||
+ * TBDXXX: With current code, the IP stack ends up looking
|
||
+ * at misaligned headers with word operations. The misaligned
|
||
+ * reads are software-emulated via handle_adel_int. We'd
|
||
+ * rather align the buffers on a 16-bit boundary, but the
|
||
+ * DMA engine doesn't permit it???
|
||
+ */
|
||
+
|
||
+#ifdef CONFIG_VLAN_8021Q
|
||
+#define ETH_MAX_MTU 1522
|
||
+#define HLEN 18
|
||
+#else
|
||
+#define ETH_MAX_MTU 1518
|
||
+#define HLEN ETH_HLEN
|
||
+#endif
|
||
+
|
||
+#define AE531X_RX_BUF_SIZE \
|
||
+ (((2 + RXBUFF_RESERVE + HLEN + ETH_MAX_MTU + PHY_TRAILER_SIZE) + 3) & ~3)
|
||
+
|
||
+/* Forward references to local functions */
|
||
+static void ae531x_TxReap(ae531x_MAC_state_t *MAC_state);
|
||
+static int ae531x_phy_poll(void *data);
|
||
+static int ae531x_MAC_stop(struct net_device *dev);
|
||
+static int ae531x_MAC_open(struct net_device *dev);
|
||
+
|
||
+/* Global to track number of MACs */
|
||
+
|
||
+int ar531x_num_enet_macs;
|
||
+
|
||
+#undef DEBUG_VENETDEV
|
||
+#define AR531X_NAPI
|
||
+
|
||
+#if defined(CONFIG_VENETDEV) && defined(DEBUG_VENETDEV)
|
||
+static int cloned_counter;
|
||
+static int expand_counter;
|
||
+static int both_counter;
|
||
+#endif
|
||
+
|
||
+#ifdef AR531X_NAPI
|
||
+/*******************************************************************************
|
||
+* ae531x_MAC_poll checks for received packets, and sends data
|
||
+* up the stack.
|
||
+*/
|
||
+int
|
||
+ae531x_MAC_poll(struct net_device *dev, int *budget)
|
||
+{
|
||
+ struct sk_buff *skb;
|
||
+ struct sk_buff *newskb;
|
||
+ char *rxBufp;
|
||
+ int unused_length;
|
||
+ VIRT_ADDR rxDesc;
|
||
+ int length;
|
||
+ ae531x_dev_sw_state_t *dev_sw_state;
|
||
+ ae531x_MAC_state_t *MAC_state;
|
||
+ ae531x_MAC_t *MACInfo;
|
||
+ u32 cmdsts;
|
||
+ int rx_limit;
|
||
+ int rx_received;
|
||
+ int rxDescCount;
|
||
+ struct net_device *rxdev;
|
||
+ int early_stop;
|
||
+ int retval;
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ int i;
|
||
+#endif
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
|
||
+ MAC_state = dev_sw_state->MAC_state;
|
||
+ MACInfo = &MAC_state->MACInfo;
|
||
+ rx_limit = MAC_state->dev_sw_state[MAC_state->primary_dev]->dev->quota;
|
||
+ rx_received = 0;
|
||
+
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ /*
|
||
+ * Non-primary devs don't explicitly get polled by the upper layers;
|
||
+ * rather, they rely on primary_dev polling to feed packets. But in
|
||
+ * order to keep netif_receive_skb happy, we need to temporarily put the
|
||
+ * net_devices into "polling mode". We pull them back out before
|
||
+ * leaving this function.
|
||
+ */
|
||
+ for (i=0; i<AE531X_DEV_PER_MAC; i++) {
|
||
+ if ((MAC_state->dev_sw_state[i]->dev) &&
|
||
+ (MAC_state->dev_sw_state[i]->unit_on_MAC != MAC_state->primary_dev)) {
|
||
+ netif_rx_schedule(MAC_state->dev_sw_state[i]->dev);
|
||
+ }
|
||
+ }
|
||
+#endif
|
||
+ rxDescCount = 0;
|
||
+
|
||
+ early_stop = 0;
|
||
+ do {
|
||
+ for(;;) {
|
||
+ // ae531x_AckIntr(MACInfo, (DmaIntRxCompleted | DmaIntRxNoBuffer));
|
||
+
|
||
+ rxDesc = MACInfo->rxQueue.curDescAddr;
|
||
+ cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(rxDesc));
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_RX,
|
||
+ ("examine rxDesc %p with cmdsts=0x%x\n",
|
||
+ (void *)rxDesc, cmdsts));
|
||
+
|
||
+ if (cmdsts & DescOwnByDma) {
|
||
+ /* There's nothing left to process in the RX ring */
|
||
+ goto rx_all_done;
|
||
+ }
|
||
+
|
||
+ rxDescCount++;
|
||
+
|
||
+ AE531X_CONSUME_DESC((&MACInfo->rxQueue));
|
||
+
|
||
+ // A_DATA_CACHE_INVAL(rxDesc, AE531X_DESC_SIZE);
|
||
+
|
||
+ /* Process a packet */
|
||
+ length = AE531X_DESC_STATUS_RX_SIZE(cmdsts) - ETH_CRC_LEN;
|
||
+ if ( (cmdsts & (DescRxFirst |DescRxLast | DescRxErrors)) ==
|
||
+ (DescRxFirst | DescRxLast) ) {
|
||
+ /* Descriptor status indicates "NO errors" */
|
||
+ skb = AE531X_DESC_SWPTR_GET(rxDesc);
|
||
+
|
||
+ /*
|
||
+ * Allocate a replacement skb.
|
||
+ * We want to get another buffer ready for Rx ASAP.
|
||
+ */
|
||
+ newskb = (struct sk_buff *)ae531x_rxbuf_alloc(MACInfo, &rxBufp, &unused_length);
|
||
+ if(newskb == NULL ) {
|
||
+ /*
|
||
+ * Give this descriptor back to the DMA engine,
|
||
+ * and drop the received packet.
|
||
+ */
|
||
+ MAC_state->stats.rx_dropped++;
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("Can't allocate new skb\n"));
|
||
+ } else {
|
||
+ AE531X_DESC_BUFPTR_SET(rxDesc, rxBufp);
|
||
+ AE531X_DESC_SWPTR_SET(rxDesc, newskb);
|
||
+ }
|
||
+
|
||
+ AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma);
|
||
+ A_DATA_CACHE_FLUSH_INVAL(rxDesc, AE531X_DESC_SIZE);
|
||
+ // rxDesc = NULL; /* sanity -- cannot use rxDesc now */
|
||
+ sysWbFlush();
|
||
+
|
||
+ if (newskb == NULL) {
|
||
+ retval = 1;
|
||
+ goto rx_no_skbs;
|
||
+ } else {
|
||
+ /* Sync data cache w.r.t. DMA */
|
||
+ // A_DATA_CACHE_INVAL(skb->data, length);
|
||
+
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ /* Determine which associated device owns this rx buffer */
|
||
+ {
|
||
+ int fromLAN;
|
||
+
|
||
+ fromLAN = phyDetermineSource(skb->data, length);
|
||
+
|
||
+ if (fromLAN == -1) {
|
||
+ /*
|
||
+ * Could not determine source, so drop the packet
|
||
+ */
|
||
+ dev_kfree_skb(skb);
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ length -= PHY_TRAILER_SIZE;
|
||
+ if (fromLAN) {
|
||
+ dev_sw_state = MAC_state->dev_sw_state[AE531X_LAN_PORT];
|
||
+ } else {
|
||
+ dev_sw_state = MAC_state->dev_sw_state[AE531X_WAN_PORT];
|
||
+ }
|
||
+ }
|
||
+#endif
|
||
+ rxdev = dev_sw_state->dev;
|
||
+
|
||
+ if (rxdev == NULL) {
|
||
+ /*
|
||
+ * We received a packet for a virtual enet device
|
||
+ * that is no longer up. Ignore it.
|
||
+ */
|
||
+ dev_kfree_skb(skb);
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ /* Advance data pointer to show that there's data here */
|
||
+ skb_put(skb, length);
|
||
+ skb->protocol = eth_type_trans(skb, rxdev);
|
||
+ skb->dev = rxdev;
|
||
+ rxdev->last_rx = jiffies;
|
||
+ rxdev->quota--;
|
||
+
|
||
+ if (rx_limit-- < 0) {
|
||
+ early_stop=1;
|
||
+ /* We've done enough for now -- more later */
|
||
+ AE531X_PRINT(AE531X_DEBUG_RX_STOP,
|
||
+ ("Enet%d RX early stop. Quota=%d rxDescCount=%d budget=%d\n",
|
||
+ MACInfo->unit, dev->quota, rxDescCount, *budget));
|
||
+ }
|
||
+ rx_received++;
|
||
+
|
||
+ /* Send the data up the stack */
|
||
+ AE531X_PRINT(AE531X_DEBUG_RX,
|
||
+ ("Send data up stack: skb=%p data=%p length=%d\n",
|
||
+ (void *)skb, (void *)skb->data, length));
|
||
+
|
||
+ netif_receive_skb(skb);
|
||
+
|
||
+ MAC_state->stats.rx_packets++;
|
||
+ MAC_state->stats.rx_bytes += length;
|
||
+ }
|
||
+ } else {
|
||
+ /* Descriptor status indicates ERRORS */
|
||
+ MAC_state->stats.rx_errors++;
|
||
+
|
||
+ if (cmdsts & (DescRxRunt | DescRxLateColl)) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("Runt | RX Late Collision Error\n"));
|
||
+ MAC_state->stats.collisions++;
|
||
+ }
|
||
+
|
||
+ if (cmdsts & DescRxLengthError) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("RX Length Error\n"));
|
||
+ MAC_state->stats.rx_length_errors++;
|
||
+ }
|
||
+
|
||
+ if (cmdsts & DescRxCrc) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("RX CRC Error\n"));
|
||
+ MAC_state->stats.rx_crc_errors++;
|
||
+ }
|
||
+
|
||
+ if (cmdsts & DescRxDribbling) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("Dribbling Error\n"));
|
||
+ MAC_state->stats.rx_frame_errors++;
|
||
+ }
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("Bad receive. rxDesc=%p cmdsts=0x%8.8x\n",
|
||
+ (void *)rxDesc, cmdsts));
|
||
+
|
||
+ /* Give this one back */
|
||
+ AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma);
|
||
+ A_DATA_CACHE_FLUSH_INVAL(rxDesc, AE531X_DESC_SIZE);
|
||
+ sysWbFlush();
|
||
+ }
|
||
+ }
|
||
+ } while ((!early_stop) &&
|
||
+ ae531x_ReadDmaReg(MACInfo, DmaStatus) & DmaIntRxCompleted);
|
||
+
|
||
+rx_all_done:
|
||
+ AE531X_PRINT(AE531X_DEBUG_RX,
|
||
+ ("rx done (%d)\n", rxDescCount));
|
||
+ *budget -= rxDescCount;
|
||
+
|
||
+ if (!early_stop) {
|
||
+ netif_rx_complete(dev);
|
||
+
|
||
+ ae531x_SetDmaReg(MACInfo, DmaIntrEnb,
|
||
+ DmaIeRxCompleted | DmaIeRxNoBuffer);
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaRxPollDemand, 0);
|
||
+ }
|
||
+
|
||
+ retval = early_stop;
|
||
+
|
||
+rx_no_skbs:
|
||
+
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ for (i=0; i<AE531X_DEV_PER_MAC; i++) {
|
||
+ if ((MAC_state->dev_sw_state[i]->dev) &&
|
||
+ (MAC_state->dev_sw_state[i]->unit_on_MAC !=
|
||
+ MAC_state->primary_dev)) {
|
||
+ netif_rx_complete(MAC_state->dev_sw_state[i]->dev);
|
||
+ }
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ LEAVE();
|
||
+ return retval;
|
||
+}
|
||
+#endif
|
||
+
|
||
+#ifndef AR531X_NAPI
|
||
+/*******************************************************************************
|
||
+* ae531x_MAC_recv checks for received packets, and sends data
|
||
+* up the stack.
|
||
+*/
|
||
+static void
|
||
+ae531x_MAC_recv(struct net_device *dev)
|
||
+{
|
||
+ struct sk_buff *skb;
|
||
+ struct sk_buff *newskb;
|
||
+ char *rxBufp;
|
||
+ int unused_length;
|
||
+ VIRT_ADDR rxDesc;
|
||
+ int length;
|
||
+ ae531x_dev_sw_state_t *dev_sw_state;
|
||
+ ae531x_MAC_state_t *MAC_state;
|
||
+ ae531x_MAC_t *MACInfo;
|
||
+ u32 cmdsts;
|
||
+ int rx_limit;
|
||
+ int rx_received;
|
||
+ struct net_device *rxdev;
|
||
+ int retval;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
|
||
+ MAC_state = dev_sw_state->MAC_state;
|
||
+ MACInfo = &MAC_state->MACInfo;
|
||
+ rx_limit = MAC_state->dev_sw_state[MAC_state->primary_dev]->dev->quota;
|
||
+ rx_received = 0;
|
||
+
|
||
+ for(;;) {
|
||
+ rxDesc = MACInfo->rxQueue.curDescAddr;
|
||
+ cmdsts = AE531X_DESC_STATUS_GET(KSEG1ADDR(rxDesc));
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_RX,
|
||
+ ("examine rxDesc %p with cmdsts=0x%x\n",
|
||
+ (void *)rxDesc, cmdsts));
|
||
+
|
||
+ if (cmdsts & DescOwnByDma) {
|
||
+ /* There's nothing left to process in the RX ring */
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ AE531X_CONSUME_DESC((&MACInfo->rxQueue));
|
||
+
|
||
+ // A_DATA_CACHE_INVAL(rxDesc, AE531X_DESC_SIZE);
|
||
+
|
||
+ /* Process a packet */
|
||
+ length = AE531X_DESC_STATUS_RX_SIZE(cmdsts) - ETH_CRC_LEN;
|
||
+ if ( (cmdsts & (DescRxFirst |DescRxLast | DescRxErrors)) ==
|
||
+ (DescRxFirst | DescRxLast) ) {
|
||
+ /* Descriptor status indicates "NO errors" */
|
||
+ skb = AE531X_DESC_SWPTR_GET(rxDesc);
|
||
+
|
||
+ /*
|
||
+ * Allocate a replacement skb.
|
||
+ * We want to get another buffer ready for Rx ASAP.
|
||
+ */
|
||
+ newskb = (struct sk_buff *)ae531x_rxbuf_alloc(MACInfo,
|
||
+ &rxBufp,
|
||
+ &unused_length);
|
||
+ if(newskb == NULL ) {
|
||
+ /*
|
||
+ * Give this descriptor back to the DMA engine,
|
||
+ * and drop the received packet.
|
||
+ */
|
||
+ MAC_state->stats.rx_dropped++;
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("Can't allocate new skb\n"));
|
||
+ } else {
|
||
+ AE531X_DESC_BUFPTR_SET(rxDesc, rxBufp);
|
||
+ AE531X_DESC_SWPTR_SET(rxDesc, newskb);
|
||
+ }
|
||
+
|
||
+ AE531X_DESC_STATUS_SET(rxDesc, DescOwnByDma);
|
||
+ A_DATA_CACHE_FLUSH_INVAL(rxDesc, AE531X_DESC_SIZE);
|
||
+ sysWbFlush();
|
||
+
|
||
+ if (newskb == NULL) {
|
||
+ break;
|
||
+ } else {
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ /* Determine which associated device owns this rx buffer */
|
||
+ {
|
||
+ int fromLAN;
|
||
+
|
||
+ fromLAN = phyDetermineSource(skb->data, length);
|
||
+
|
||
+ if (fromLAN == -1) {
|
||
+ /*
|
||
+ * Could not determine source, so drop the packet
|
||
+ */
|
||
+ dev_kfree_skb(skb);
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ length -= PHY_TRAILER_SIZE;
|
||
+ if (fromLAN) {
|
||
+ dev_sw_state =
|
||
+ MAC_state->dev_sw_state[AE531X_LAN_PORT];
|
||
+ } else {
|
||
+ dev_sw_state =
|
||
+ MAC_state->dev_sw_state[AE531X_WAN_PORT];
|
||
+ }
|
||
+ }
|
||
+#endif
|
||
+ rxdev = dev_sw_state->dev;
|
||
+
|
||
+ if (rxdev == NULL) {
|
||
+ /*
|
||
+ * We received a packet for a virtual enet device
|
||
+ * that is no longer up. Ignore it.
|
||
+ */
|
||
+ dev_kfree_skb(skb);
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ /* Advance data pointer to show that there's data here */
|
||
+ skb_put(skb, length);
|
||
+ skb->protocol = eth_type_trans(skb, rxdev);
|
||
+ skb->dev = rxdev;
|
||
+ rxdev->last_rx = jiffies;
|
||
+ rxdev->quota--;
|
||
+
|
||
+ rx_received++;
|
||
+
|
||
+ /* Send the data up the stack */
|
||
+ AE531X_PRINT(AE531X_DEBUG_RX,
|
||
+ ("Send data up stack: skb=%p data=%p length=%d\n",
|
||
+ (void *)skb, (void *)skb->data, length));
|
||
+
|
||
+ netif_rx(skb);
|
||
+
|
||
+ MAC_state->stats.rx_packets++;
|
||
+ MAC_state->stats.rx_bytes += length;
|
||
+ }
|
||
+ } else {
|
||
+ /* Descriptor status indicates ERRORS */
|
||
+ MAC_state->stats.rx_errors++;
|
||
+
|
||
+ if (cmdsts & (DescRxRunt | DescRxLateColl)) {
|
||
+ MAC_state->stats.collisions++;
|
||
+ }
|
||
+
|
||
+ if (cmdsts & DescRxLengthError) {
|
||
+ MAC_state->stats.rx_length_errors++;
|
||
+ }
|
||
+
|
||
+ if (cmdsts & DescRxCrc) {
|
||
+ MAC_state->stats.rx_crc_errors++;
|
||
+ }
|
||
+
|
||
+ if (cmdsts & DescRxDribbling) {
|
||
+ MAC_state->stats.rx_frame_errors++;
|
||
+ }
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("Bad receive. rxDesc=%p cmdsts=0x%8.8x\n",
|
||
+ (void *)rxDesc, cmdsts));
|
||
+ }
|
||
+ }
|
||
+
|
||
+ LEAVE();
|
||
+ return;
|
||
+}
|
||
+#endif
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_restart stops all ethernet devices associated with a physical MAC,
|
||
+* then shuts down the MAC. Then it re-opens all devices that were in use.
|
||
+* TBDXXX: needs testing!
|
||
+*/
|
||
+static void
|
||
+ae531x_restart(void *data)
|
||
+{
|
||
+ ae531x_MAC_t *MACInfo = (ae531x_MAC_t *)data;
|
||
+ ae531x_MAC_state_t *MAC_state = (ae531x_MAC_state_t *)MACInfo->OSinfo;
|
||
+ struct net_device *saved_dev[AE531X_DEV_PER_MAC];
|
||
+ int i;
|
||
+
|
||
+ for (i=0; i<AE531X_DEV_PER_MAC; i++) {
|
||
+ if ((saved_dev[i] = MAC_state->dev_sw_state[i]->dev) != NULL) {
|
||
+ ae531x_MAC_stop(saved_dev[i]);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ for (i=0; i<AE531X_DEV_PER_MAC; i++) {
|
||
+ if (saved_dev[i])
|
||
+ ae531x_MAC_open(saved_dev[i]);
|
||
+ }
|
||
+}
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_MAC_intr handle interrupts from an ethernet MAC.
|
||
+* It checks MAC status registers, and dispatches as appropriate.
|
||
+*/
|
||
+void
|
||
+ae531x_MAC_intr(int cpl, void *dev_id, struct pt_regs *regs)
|
||
+{
|
||
+ ae531x_MAC_state_t *MAC_state;
|
||
+ ae531x_MAC_t *MACInfo;
|
||
+ u32 regIsr;
|
||
+ u32 regImr;
|
||
+ u32 pendIntrs;
|
||
+ struct net_device * primary_dev;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ MACInfo = (ae531x_MAC_t *)dev_id;
|
||
+ MAC_state = (ae531x_MAC_state_t *)MACInfo->OSinfo;
|
||
+ primary_dev = MAC_state->dev_sw_state[MAC_state->primary_dev]->dev;
|
||
+
|
||
+ for(;;) {
|
||
+ /* Clear any unhandled intr causes. */
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaStatus, UnhandledIntrMask);
|
||
+
|
||
+ regIsr = ae531x_ReadDmaReg(MACInfo, DmaStatus);
|
||
+
|
||
+ regImr = ae531x_ReadDmaReg(MACInfo, DmaIntrEnb);
|
||
+ pendIntrs = regIsr & regImr;
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_INT,
|
||
+ ("ethmac%d: intIsr=0x%8.8x intImr=0x%8.8x\n",
|
||
+ MACInfo->unit, regIsr, regImr));
|
||
+
|
||
+ if ((pendIntrs & DmaAllIntCauseMask) == 0)
|
||
+ break;
|
||
+
|
||
+ if ((pendIntrs & DmaIntRxCompleted) ||
|
||
+ (pendIntrs & DmaIntRxNoBuffer)) {
|
||
+#ifdef AR531X_NAPI
|
||
+ if (netif_rx_schedule_prep(primary_dev)) {
|
||
+ ae531x_ClearDmaReg(MACInfo,
|
||
+ DmaIntrEnb,
|
||
+ DmaIeRxCompleted | DmaIeRxNoBuffer);
|
||
+ ae531x_AckIntr(MACInfo,
|
||
+ DmaIntRxCompleted | DmaIntRxNoBuffer);
|
||
+ (void)ae531x_ReadDmaReg(MACInfo, DmaIntrEnb);
|
||
+ __netif_rx_schedule(primary_dev);
|
||
+ } else {
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("%s: Interrupt (0x%8.8x/0x%8.8x) while in poll. regs@%p, pc=%p, ra=%p\n",
|
||
+ __FILE__,
|
||
+ regIsr,
|
||
+ ae531x_ReadDmaReg(MACInfo, DmaIntrEnb),
|
||
+ (void *)regs,
|
||
+ (void *)regs->cp0_epc,
|
||
+ (void *)regs->regs[31]));
|
||
+ ae531x_ClearDmaReg(MACInfo,
|
||
+ DmaIntrEnb,
|
||
+ DmaIeRxCompleted | DmaIeRxNoBuffer);
|
||
+ ae531x_AckIntr(MACInfo,
|
||
+ DmaIntRxCompleted | DmaIntRxNoBuffer);
|
||
+ }
|
||
+#else
|
||
+ ae531x_MAC_recv(primary_dev);
|
||
+ ae531x_AckIntr(MACInfo,
|
||
+ DmaIntRxCompleted | DmaIntRxNoBuffer);
|
||
+#endif
|
||
+ }
|
||
+
|
||
+ if (pendIntrs &
|
||
+ (DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow)) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("ethmac%d: TX Error Intr (0x%x)\n",
|
||
+ MACInfo->unit, pendIntrs));
|
||
+ ae531x_AckIntr(MACInfo,
|
||
+ (DmaIntTxStopped | DmaIntTxJabber | DmaIntTxUnderflow));
|
||
+ }
|
||
+
|
||
+ if (pendIntrs & DmaIntBusError) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("ethmac%d: DMA Bus Error Intr (0x%x)\n",
|
||
+ MACInfo->unit, pendIntrs));
|
||
+ ae531x_AckIntr(MACInfo, DmaIntBusError);
|
||
+ /* Reset the chip, if it's not already being done */
|
||
+ if (ae531x_IsInResetMode(MACInfo)) {
|
||
+ goto intr_done;
|
||
+ }
|
||
+ ae531x_BeginResetMode(MACInfo);
|
||
+ schedule_task(&MAC_state->restart_task);
|
||
+ }
|
||
+
|
||
+ if (pendIntrs & DmaIntRxStopped) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("ethmac%d: RX Stopped Intr (0x%x)\n",
|
||
+ MACInfo->unit, pendIntrs));
|
||
+ ae531x_AckIntr(MACInfo, DmaIntRxStopped);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ ae531x_DmaIntEnable(MACInfo);
|
||
+
|
||
+intr_done:
|
||
+ LEAVE();
|
||
+}
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_MAC_get_stats returns statistics for a specified device
|
||
+*/
|
||
+static struct net_device_stats*
|
||
+ae531x_MAC_get_stats(struct net_device *dev)
|
||
+{
|
||
+ ae531x_dev_sw_state_t *dev_sw_state;
|
||
+ ae531x_MAC_state_t *MAC_state;
|
||
+
|
||
+ ARRIVE();
|
||
+ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
|
||
+ MAC_state = dev_sw_state->MAC_state;
|
||
+
|
||
+ LEAVE();
|
||
+ return &MAC_state->stats;
|
||
+}
|
||
+
|
||
+#define AE531X_PHY_POLL_SECONDS 2
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_phy_poll periodically checks for changes in phy status
|
||
+* (e.g. dropped link).
|
||
+*/
|
||
+static int
|
||
+ae531x_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 defined(CONFIG_VENETDEV) && defined(DEBUG_VENETDEV)
|
||
+ int previous_cloned = 0;
|
||
+ int previous_expand = 0;
|
||
+ int previous_both = 0;
|
||
+#endif
|
||
+
|
||
+ daemonize();
|
||
+ reparent_to_init();
|
||
+ spin_lock_irq(¤t->sigmask_lock);
|
||
+ sigemptyset(¤t->blocked);
|
||
+ recalc_sigpending(current);
|
||
+ spin_unlock_irq(¤t->sigmask_lock);
|
||
+
|
||
+ snprintf(current->comm, sizeof(current->comm), "%s",
|
||
+ dev_sw_state->dev->name);
|
||
+
|
||
+ for(;;) {
|
||
+ if (MACInfo->port_is_up) {
|
||
+ phyCheckStatusChange(unit);
|
||
+ }
|
||
+
|
||
+#if defined(CONFIG_VENETDEV) && defined(DEBUG_VENETDEV)
|
||
+ if (cloned_counter != previous_cloned) {
|
||
+ printk("Cloned Counter: %d (delta %d)\n",
|
||
+ cloned_counter, cloned_counter - previous_cloned);
|
||
+ previous_cloned = cloned_counter;
|
||
+ }
|
||
+ if (expand_counter != previous_expand) {
|
||
+ printk("Expand Counter: %d (delta %d)\n",
|
||
+ expand_counter, expand_counter - previous_expand);
|
||
+ previous_expand = expand_counter;
|
||
+ }
|
||
+ if (both_counter != previous_both) {
|
||
+ printk("Expand & Cloned Counter: %d (delta %d)\n",
|
||
+ both_counter, both_counter - previous_both);
|
||
+ previous_both = both_counter;
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ set_current_state(TASK_UNINTERRUPTIBLE);
|
||
+ schedule_timeout(AE531X_PHY_POLL_SECONDS * HZ);
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_MAC_set_rx_mode is used to set the RX mode options, such as
|
||
+* promiscuous or multicast.
|
||
+*/
|
||
+static void
|
||
+ae531x_MAC_set_rx_mode(struct net_device *dev)
|
||
+{
|
||
+ ae531x_dev_sw_state_t *dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
|
||
+ ae531x_MAC_state_t *MAC_state=dev_sw_state->MAC_state;
|
||
+ ae531x_MAC_t *MACInfo = &MAC_state->MACInfo;
|
||
+
|
||
+ if (dev->flags & IFF_PROMISC) {
|
||
+ ae531x_SetMacReg(MACInfo, MacControl, MacPromiscuousModeOn);
|
||
+ } else {
|
||
+ ae531x_ClearMacReg(MACInfo, MacControl, MacPromiscuousModeOn);
|
||
+ }
|
||
+
|
||
+ if (dev->flags & IFF_MULTICAST) {
|
||
+ ae531x_SetMacReg(MACInfo, MacControl, MacMulticastFilterOff);
|
||
+ } else {
|
||
+ ae531x_ClearMacReg(MACInfo, MacControl, MacMulticastFilterOff);
|
||
+ }
|
||
+}
|
||
+
|
||
+/*******************************************************************************
|
||
+* 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;
|
||
+ 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));
|
||
+
|
||
+ if (!MACInfo->port_is_up) {
|
||
+ /* Bring MAC and PHY out of reset */
|
||
+ 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 */
|
||
+ phySetup(MACInfo->unit, MACInfo->phyBase);
|
||
+
|
||
+ /* Start thread to poll for phy link status changes */
|
||
+ phy_poll_pid = kernel_thread(ae531x_phy_poll,
|
||
+ dev_sw_state,
|
||
+ CLONE_FS | CLONE_FILES);
|
||
+ if (phy_poll_pid < 0) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("ethmac%d unable to start Phy Poll thread\n",
|
||
+ MACInfo->unit));
|
||
+ }
|
||
+
|
||
+ /* 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);
|
||
+
|
||
+ /* Set RX mode */
|
||
+ ae531x_MAC_set_rx_mode(dev);
|
||
+
|
||
+ /* Enable Receive/Transmit */
|
||
+ ae531x_EnableComm(MACInfo);
|
||
+
|
||
+ MAC_state->primary_dev = dev_sw_state->unit_on_MAC;
|
||
+ MACInfo->port_is_up = TRUE;
|
||
+ }
|
||
+
|
||
+ dev->trans_start = jiffies;
|
||
+
|
||
+ LEAVE();
|
||
+ return 0;
|
||
+
|
||
+open_failure:
|
||
+ LEAVE();
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Shut down MAC hardware.
|
||
+ */
|
||
+static void
|
||
+ae531x_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);
|
||
+
|
||
+ /* Free Transmit & Receive skb's/descriptors */
|
||
+ ae531x_TxReap(MAC_state); /* 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 int
|
||
+ae531x_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;
|
||
+
|
||
+ 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 {
|
||
+ /* 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)
|
||
+{
|
||
+ struct sk_buff *skb;
|
||
+ char *rxBuff;
|
||
+ int rxBuffSize;
|
||
+
|
||
+ skb = dev_alloc_skb(AE531X_RX_BUF_SIZE);
|
||
+ if (skb) {
|
||
+ /* Add 2 to align the IP header on a DWORD boundary */
|
||
+ skb_reserve(skb, RXBUFF_RESERVE + 2);
|
||
+
|
||
+ rxBuffSize = skb_tailroom(skb);
|
||
+ rxBuff = skb->tail;
|
||
+
|
||
+ *rxBuffp = rxBuff;
|
||
+ *rxBuffSizep = rxBuffSize;
|
||
+
|
||
+ A_DATA_CACHE_INVAL(rxBuff, rxBuffSize);
|
||
+ }
|
||
+
|
||
+ return skb;
|
||
+}
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_swptr_free - Free the skb, if any, associated with a descriptor.
|
||
+*/
|
||
+void
|
||
+ae531x_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 void
|
||
+ae531x_TxReap(ae531x_MAC_state_t *MAC_state)
|
||
+{
|
||
+ AE531X_QUEUE *txq;
|
||
+ VIRT_ADDR txDesc;
|
||
+ UINT32 cmdsts;
|
||
+ struct sk_buff *skb;
|
||
+ int reaped;
|
||
+ ae531x_MAC_t *MACInfo;
|
||
+ static int aeUselessReap = 0;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ MACInfo = &MAC_state->MACInfo;
|
||
+ txq = &MACInfo->txQueue;
|
||
+ 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);
|
||
+ }
|
||
+
|
||
+ /* 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));
|
||
+ 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 += AE531X_DESC_STATUS_RX_SIZE(cmdsts);
|
||
+ MAC_state->stats.tx_packets++;
|
||
+ }
|
||
+
|
||
+ MAC_state->stats.collisions +=
|
||
+ ((cmdsts & DescTxCollMask) >> DescTxCollShift);
|
||
+
|
||
+ txq->reapDescAddr = txDesc;
|
||
+ reaped++;
|
||
+ }
|
||
+
|
||
+ if (reaped > 0) {
|
||
+ int i;
|
||
+
|
||
+ 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 int
|
||
+ae531x_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;
|
||
+ int mtu;
|
||
+ int max_buf_size;
|
||
+ VIRT_ADDR txDesc;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
|
||
+ MAC_state = dev_sw_state->MAC_state;
|
||
+ MACInfo = &MAC_state->MACInfo;
|
||
+
|
||
+ 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;
|
||
+ }
|
||
+
|
||
+ /* Check if we can transport this packet */
|
||
+ length = max((u32)60, length); /* total length */
|
||
+ mtu = dev->mtu;
|
||
+ max_buf_size = mtu + 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;
|
||
+ }
|
||
+
|
||
+ /* Reap any old, completed Tx descriptors */
|
||
+ ae531x_TxReap(MAC_state);
|
||
+
|
||
+ 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.
|
||
+ */
|
||
+ 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);
|
||
+ }
|
||
+ goto dropFrame;
|
||
+ }
|
||
+
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ {
|
||
+ struct sk_buff *newskb;
|
||
+
|
||
+ if (skb_cloned(skb) || (skb_tailroom(skb) < PHY_TRAILER_SIZE)) {
|
||
+#ifdef DEBUG_VENETDEV
|
||
+ if (skb_cloned(skb)) {
|
||
+ cloned_counter++;
|
||
+ if (skb_tailroom(skb) < PHY_TRAILER_SIZE) {
|
||
+ both_counter++;
|
||
+ }
|
||
+ } else {
|
||
+ expand_counter++;
|
||
+ }
|
||
+#endif
|
||
+ newskb = skb_copy_expand(skb, 0, PHY_TRAILER_SIZE, GFP_ATOMIC);
|
||
+ if (newskb == NULL) {
|
||
+ goto dropFrame;
|
||
+ }
|
||
+
|
||
+ dev_kfree_skb(skb);
|
||
+ skb = newskb;
|
||
+ }
|
||
+
|
||
+ phySetDestinationPort(skb->data, length, dev_sw_state->isLAN);
|
||
+ skb_put(skb, PHY_TRAILER_SIZE);
|
||
+ length += PHY_TRAILER_SIZE;
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ /* We won't fail now; so consume this descriptor */
|
||
+ AE531X_CONSUME_DESC((&MACInfo->txQueue));
|
||
+
|
||
+ /* Update the descriptor */
|
||
+ buf = virt_to_bus(skb->data);
|
||
+ A_DATA_CACHE_FLUSH(skb->data, skb->len);
|
||
+ AE531X_DESC_BUFPTR_SET(txDesc, buf);
|
||
+ AE531X_DESC_SWPTR_SET(txDesc, skb);
|
||
+ ctrlen = AE531X_DESC_CTRLEN_GET(txDesc);
|
||
+ ctrlen = (ctrlen & (DescEndOfRing)) |
|
||
+ DescTxFirst |
|
||
+ DescTxLast |
|
||
+ DescTxIntEnable;
|
||
+
|
||
+ ctrlen |= ((length << DescSize1Shift) & DescSize1Mask);
|
||
+
|
||
+ AE531X_DESC_CTRLEN_SET(txDesc, ctrlen);
|
||
+ AE531X_DESC_STATUS_SET(txDesc, DescOwnByDma);
|
||
+
|
||
+ 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));
|
||
+
|
||
+ /* Must not use txDesc after this point */
|
||
+ A_DATA_CACHE_FLUSH_INVAL(txDesc, AE531X_DESC_SIZE);
|
||
+
|
||
+ /* Alert DMA engine to resume Tx */
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaTxPollDemand, 0);
|
||
+ sysWbFlush();
|
||
+
|
||
+ MAC_state->stats.tx_packets++;
|
||
+ MAC_state->stats.tx_bytes += length;
|
||
+
|
||
+ /* Tell upper layers to keep it coming */
|
||
+ dev->trans_start = jiffies;
|
||
+
|
||
+ LEAVE();
|
||
+ return 0;
|
||
+
|
||
+dropFrame:
|
||
+ dev_kfree_skb(skb);
|
||
+
|
||
+ LEAVE();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_MAC_tx_timeout handles transmit timeouts
|
||
+*/
|
||
+static void
|
||
+ae531x_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.
|
||
+*/
|
||
+static int
|
||
+ae531x_MAC_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||
+{
|
||
+ int rv;
|
||
+ ae531x_MAC_t *MACInfo;
|
||
+ struct ioctl_data {
|
||
+ u32 unit;
|
||
+ u32 addr;
|
||
+ u32 data;
|
||
+ } *req;
|
||
+ ae531x_dev_sw_state_t *dev_sw_state;
|
||
+ ae531x_MAC_state_t *MAC_state;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ dev_sw_state = (ae531x_dev_sw_state_t *)dev->priv;
|
||
+ MAC_state = dev_sw_state->MAC_state;
|
||
+ MACInfo = &MAC_state->MACInfo;
|
||
+
|
||
+ req = (struct ioctl_data *)ifr->ifr_data;
|
||
+
|
||
+ switch( cmd ) {
|
||
+ default:
|
||
+ AE531X_PRINT(AE531X_DEBUG_ERROR,
|
||
+ ("Unsupported ioctl: 0x%x\n", cmd));
|
||
+ rv = -EOPNOTSUPP;
|
||
+ }
|
||
+
|
||
+ LEAVE();
|
||
+ return rv;
|
||
+}
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_MAC_set_mac_address sets a new hardware address for the device
|
||
+*/
|
||
+static int
|
||
+ae531x_MAC_set_mac_address(struct net_device *dev, void *addr)
|
||
+{
|
||
+ struct sockaddr *saddr = (struct sockaddr *)addr;
|
||
+
|
||
+ /* update dev struct */
|
||
+ memcpy(dev->dev_addr, &saddr->sa_data[0], dev->addr_len);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/******************************************************************************
|
||
+* macAddrGet - Given a MACInfo pointer, return a pointer to an
|
||
+* array of chars that holds the corresponding MAC address.
|
||
+*/
|
||
+char *macAddrGet(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ // return enet_mac_address_get(MACInfo->unit);
|
||
+ return ae531x_MAC_dev[MACInfo->unit]->dev_addr;
|
||
+}
|
||
+
|
||
+static void
|
||
+ae531x_MAC_setup_fntable(struct net_device *dev)
|
||
+{
|
||
+ /* Set a default (should be overridden by software) */
|
||
+ u8 default_MAC_address[] = { 0x00, 0x03, 0x7f, 0xe0, 0x02, 0xbF };
|
||
+
|
||
+ 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;
|
||
+#ifdef AR531X_NAPI
|
||
+ dev->poll = ae531x_MAC_poll;
|
||
+ dev->weight = 16;
|
||
+#endif
|
||
+ dev->tx_timeout = ae531x_MAC_tx_timeout;
|
||
+ dev->features = NETIF_F_HW_CSUM |\
|
||
+ NETIF_F_HIGHDMA;
|
||
+ dev->set_mac_address = ae531x_MAC_set_mac_address;
|
||
+ dev->set_multicast_list = ae531x_MAC_set_rx_mode;
|
||
+
|
||
+ /* Copy default MAC address into device descriptor */
|
||
+ memcpy(dev->dev_addr, default_MAC_address, dev->addr_len );
|
||
+
|
||
+ LEAVE();
|
||
+}
|
||
+
|
||
+/*
|
||
+ * ae531x_twisted_enet() returns 1 for chips where there is only one usable
|
||
+ * MAC, and that MAC is 1.
|
||
+ */
|
||
+static BOOL
|
||
+ae531x_twisted_enet(void)
|
||
+{
|
||
+ int wisoc_revision;
|
||
+ int flash_bus_width;
|
||
+
|
||
+ wisoc_revision = (sysRegRead(AR531X_REV) & AR531X_REV_MAJ) >>
|
||
+ AR531X_REV_MAJ_S;
|
||
+ if (wisoc_revision == AR531X_REV_MAJ_AR2313)
|
||
+ return TRUE;
|
||
+
|
||
+ flash_bus_width = sysRegRead(AR531X_FLASHCTL0) & FLASHCTL_MWx16;
|
||
+
|
||
+ if (flash_bus_width == 0) {
|
||
+ printk("Found AR2312-01\n");
|
||
+ return TRUE; /* AR2312-01 has 8 bit flash bus */
|
||
+ } else {
|
||
+ printk("Found AR2312-00\n");
|
||
+ return FALSE;
|
||
+ }
|
||
+}
|
||
+
|
||
+int
|
||
+ae531x_MAC_setup(void)
|
||
+{
|
||
+ int i;
|
||
+ int next_dev;
|
||
+ int rev;
|
||
+ struct net_device *dev;
|
||
+ ae531x_dev_sw_state_t *dev_sw_state;
|
||
+ ae531x_MAC_state_t *MAC_state;
|
||
+ ae531x_MAC_t *MACInfo;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+#if 0
|
||
+ /*
|
||
+ * This does not work since the AR2312 and AR5312 both have the same
|
||
+ * revision information in the CPU :-(
|
||
+ */
|
||
+ rev = (sysRegRead(AR531X_REV) & AR531X_REV_CHIP);
|
||
+
|
||
+ if ((rev & AR531X_REV_MIN) == AR5312_REV_MIN_SINGLE_ENET) {
|
||
+ ar531x_num_enet_macs = 1;
|
||
+ } else {
|
||
+ ar531x_num_enet_macs = 2;
|
||
+ }
|
||
+#else
|
||
+ /*
|
||
+ * Need to select the number of ethernet MACs based on the config
|
||
+ * information (sadly)
|
||
+ */
|
||
+#ifdef CONFIG_AR5312
|
||
+ ar531x_num_enet_macs = 2;
|
||
+#else
|
||
+ ar531x_num_enet_macs = 1;
|
||
+#endif
|
||
+#endif
|
||
+
|
||
+ next_dev = 0;
|
||
+ for (i=0; i<ar531x_num_enet_macs; i++) {
|
||
+
|
||
+ 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[i];
|
||
+ dev_sw_state->MAC_state = MAC_state;
|
||
+ MAC_state->dev_sw_state[AE531X_LAN_PORT] = dev_sw_state;
|
||
+ MAC_state->primary_dev = -1;
|
||
+
|
||
+ next_dev++;
|
||
+
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ {
|
||
+ ae531x_dev_sw_state_t *lan_dev_sw_state;
|
||
+
|
||
+ lan_dev_sw_state = dev_sw_state;
|
||
+
|
||
+ 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 = 1;
|
||
+ dev_sw_state->MAC_state = MAC_state;
|
||
+ MAC_state->dev_sw_state[AE531X_WAN_PORT] = dev_sw_state;
|
||
+ lan_dev_sw_state->isLAN = TRUE; /* enet0 is LAN */
|
||
+ dev_sw_state->isLAN = FALSE ; /* enet1 is WAN */
|
||
+
|
||
+ next_dev++;
|
||
+ }
|
||
+#endif
|
||
+
|
||
+ /* Initialize per-MAC information */
|
||
+ MACInfo = &MAC_state->MACInfo;
|
||
+ MACInfo->unit = i;
|
||
+
|
||
+ if (ar531x_num_enet_macs == 1) {
|
||
+ if (ae531x_twisted_enet()) {
|
||
+ MACInfo->macBase =
|
||
+ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_MAC_OFFSET);
|
||
+ MACInfo->dmaBase =
|
||
+ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_DMA_OFFSET);
|
||
+ MACInfo->phyBase =
|
||
+ (u32)(PHYS_TO_K1(AR531X_ENET0)+AE531X_PHY_OFFSET);
|
||
+ MAC_state->irq = AR531X_IRQ_ENET1_INTRS;
|
||
+ } else {
|
||
+ 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 {
|
||
+ 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 {
|
||
+ MACInfo->macBase =
|
||
+ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_MAC_OFFSET);
|
||
+ MACInfo->dmaBase =
|
||
+ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_DMA_OFFSET);
|
||
+ MACInfo->phyBase =
|
||
+ (u32)(PHYS_TO_K1(AR531X_ENET1)+AE531X_PHY_OFFSET);
|
||
+ MAC_state->irq = AR531X_IRQ_ENET1_INTRS;
|
||
+ }
|
||
+ }
|
||
+ MACInfo->OSinfo = (void *)MAC_state;
|
||
+ }
|
||
+
|
||
+ LEAVE();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+module_init(ae531x_MAC_setup);
|
||
+
|
||
diff -urN linux-2.4.32.new/arch/mips/ar531x/ae531xmac.c linux-2.4.32.new-eth/arch/mips/ar531x/ae531xmac.c
|
||
--- linux-2.4.32.new/arch/mips/ar531x/ae531xmac.c 1970-01-01 01:00:00.000000000 +0100
|
||
+++ linux-2.4.32.new-eth/arch/mips/ar531x/ae531xmac.c 2005-12-25 11:54:20.771271672 +0000
|
||
@@ -0,0 +1,942 @@
|
||
+/*
|
||
+ * This file is subject to the terms and conditions of the GNU General Public
|
||
+ * License. See the file "COPYING" in the main directory of this archive
|
||
+ * for more details.
|
||
+ *
|
||
+ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
|
||
+ */
|
||
+
|
||
+
|
||
+/*
|
||
+ * Ethernet driver for Atheros' ae531x ethernet MAC.
|
||
+ */
|
||
+
|
||
+#if linux
|
||
+#include <linux/config.h>
|
||
+#include <linux/types.h>
|
||
+#include <linux/delay.h>
|
||
+#include <linux/netdevice.h>
|
||
+#include <linux/etherdevice.h>
|
||
+#include <linux/init.h>
|
||
+#include <asm/io.h>
|
||
+
|
||
+#include "ar531xlnx.h"
|
||
+#endif /* linux */
|
||
+
|
||
+#include "ae531xreg.h"
|
||
+#include "ae531xmac.h"
|
||
+
|
||
+int ae531x_MAC_debug = AE531X_DEBUG_ERROR;
|
||
+
|
||
+/*
|
||
+ * These externs are for functions that this layer relies on
|
||
+ * that have OS-dependent implementations.
|
||
+ */
|
||
+extern UINT8 *macAddrGet(ae531x_MAC_t *MACInfo);
|
||
+
|
||
+/* Forward references to local functions */
|
||
+static void ae531x_QueueDestroy(AE531X_QUEUE *q);
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_ReadMacReg - read AE MAC register
|
||
+*
|
||
+* RETURNS: register value
|
||
+*/
|
||
+UINT32
|
||
+ae531x_ReadMacReg(ae531x_MAC_t *MACInfo, UINT32 reg)
|
||
+{
|
||
+ UINT32 addr = MACInfo->macBase+reg;
|
||
+ UINT32 data;
|
||
+
|
||
+ data = RegRead(addr);
|
||
+ return data;
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_WriteMacReg - write AE MAC register
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_WriteMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data)
|
||
+{
|
||
+ UINT32 addr = MACInfo->macBase+reg;
|
||
+
|
||
+ RegWrite(data, addr);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_SetMacReg - set bits in AE MAC register
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_SetMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val)
|
||
+{
|
||
+ UINT32 addr = MACInfo->macBase+reg;
|
||
+ UINT32 data = RegRead(addr);
|
||
+
|
||
+ data |= val;
|
||
+ RegWrite(data, addr);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_ClearMacReg - clear bits in AE MAC register
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_ClearMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val)
|
||
+{
|
||
+ UINT32 addr = MACInfo->macBase+reg;
|
||
+ UINT32 data = RegRead(addr);
|
||
+
|
||
+ data &= ~val;
|
||
+ RegWrite(data, addr);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_ReadDmaReg - read AE DMA register
|
||
+*
|
||
+* RETURNS: register value
|
||
+*/
|
||
+UINT32
|
||
+ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg)
|
||
+{
|
||
+ UINT32 addr = MACInfo->dmaBase+reg;
|
||
+ UINT32 data = RegRead(addr);
|
||
+
|
||
+ return data;
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_WriteDmaReg - write AE DMA register
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data)
|
||
+{
|
||
+ UINT32 addr = MACInfo->dmaBase+reg;
|
||
+
|
||
+ RegWrite(data, addr);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+ *
|
||
+ * ae531x_AckIntr - clear interrupt bits in the status register.
|
||
+ * Note: Interrupt bits are *cleared* by writing a 1.
|
||
+ */
|
||
+void
|
||
+ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 data)
|
||
+{
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaStatus, data);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_SetDmaReg - set bits in an AE DMA register
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val)
|
||
+{
|
||
+ UINT32 addr = MACInfo->dmaBase+reg;
|
||
+ UINT32 data = RegRead(addr);
|
||
+
|
||
+ data |= val;
|
||
+ RegWrite(data, addr);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_ClearDmaReg - clear bits in an AE DMA register
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val)
|
||
+{
|
||
+ UINT32 addr = MACInfo->dmaBase+reg;
|
||
+ UINT32 data = RegRead(addr);
|
||
+
|
||
+ data &= ~val;
|
||
+ RegWrite(data, addr);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_ReadMiiReg - read PHY registers via AE MAC Mii addr/data registers
|
||
+*
|
||
+* RETURNS: register value
|
||
+*/
|
||
+UINT32
|
||
+ae531x_ReadMiiReg(UINT32 phyBase, UINT32 reg)
|
||
+{
|
||
+ UINT32 data;
|
||
+ UINT32 addr = phyBase+reg;
|
||
+
|
||
+ data = RegRead(addr);
|
||
+ return data;
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_WriteMiiReg - write PHY registers via AE MAC Mii addr/data registers
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_WriteMiiReg(UINT32 phyBase, UINT32 reg, UINT32 data)
|
||
+{
|
||
+ UINT32 addr = phyBase+reg;
|
||
+
|
||
+ RegWrite(data, addr);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_MiiRead - read AE Mii register
|
||
+*
|
||
+* RETURNS: register value
|
||
+*/
|
||
+UINT16
|
||
+ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg)
|
||
+{
|
||
+ UINT32 addr;
|
||
+ UINT16 data;
|
||
+
|
||
+ addr = ((phyAddr << MiiDevShift) & MiiDevMask) | ((reg << MiiRegShift) & MiiRegMask);
|
||
+
|
||
+ ae531x_WriteMiiReg(phyBase, MacMiiAddr, addr );
|
||
+ do {
|
||
+ /* nop */
|
||
+ } while ((ae531x_ReadMiiReg(phyBase, MacMiiAddr ) & MiiBusy) == MiiBusy);
|
||
+
|
||
+ data = ae531x_ReadMiiReg(phyBase, MacMiiData) & 0xFFFF;
|
||
+
|
||
+ return data;
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_MiiWrite - write AE Mii register
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg, UINT16 data)
|
||
+{
|
||
+ UINT32 addr;
|
||
+
|
||
+ ae531x_WriteMiiReg(phyBase, MacMiiData, data );
|
||
+
|
||
+ addr = ((phyAddr << MiiDevShift) & MiiDevMask) |
|
||
+ ((reg << MiiRegShift) & MiiRegMask) | MiiWrite;
|
||
+ ae531x_WriteMiiReg(phyBase, MacMiiAddr, addr );
|
||
+
|
||
+ do {
|
||
+ /* nop */
|
||
+ } while ((ae531x_ReadMiiReg(phyBase, MacMiiAddr ) & MiiBusy) == MiiBusy);
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_BeginResetMode - enter a special "reset mode" in which
|
||
+* -no interrupts are expected from the device
|
||
+* -the device will not transmit nor receive
|
||
+* -attempts to send or receive will return with an error and
|
||
+* -the device will be reset at the next convenient opportunity.
|
||
+*/
|
||
+void
|
||
+ae531x_BeginResetMode(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ /* Set the reset flag */
|
||
+ MACInfo->aeProcessRst = 1;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_EndResetMode - exit the special "reset mode" entered
|
||
+* earlier via a call to ae531x_BeginResetMode.
|
||
+*/
|
||
+void
|
||
+ae531x_EndResetMode(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ MACInfo->aeProcessRst = 0;
|
||
+}
|
||
+
|
||
+
|
||
+/*******************************************************************************
|
||
+* ae531x_IsInResetMode - determine whether or not the device is
|
||
+* currently in "reset mode" (i.e. that a device reset is pending)
|
||
+*/
|
||
+BOOL
|
||
+ae531x_IsInResetMode(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ return MACInfo->aeProcessRst;
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_DmaRxStart - Start Rx
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+static void
|
||
+ae531x_DmaRxStart(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_SetDmaReg(MACInfo, DmaControl, DmaRxStart);
|
||
+ sysWbFlush();
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_DmaRxStop - Stop Rx
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_DmaRxStop(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_ClearDmaReg(MACInfo, DmaControl, DmaRxStart);
|
||
+ sysWbFlush();
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_DmaTxStart - Start Tx
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_DmaTxStart(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_SetDmaReg(MACInfo, DmaControl, DmaTxStart);
|
||
+ sysWbFlush();
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_DmaTxStop - Stop Tx
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_DmaTxStop(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_ClearDmaReg(MACInfo, DmaControl, DmaTxStart);
|
||
+ sysWbFlush();
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_DmaIntEnable - Enable DMA interrupts
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntEnable);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_DmaIntDisable - Disable DMA interrupts
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntDisable);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_DmaIntClear - Clear DMA interrupts
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+static void
|
||
+ae531x_DmaIntClear(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ /* clear all interrupt requests */
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaStatus,
|
||
+ ae531x_ReadDmaReg(MACInfo, DmaStatus));
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* Initialize generic queue data
|
||
+*/
|
||
+void
|
||
+ae531x_QueueInit(AE531X_QUEUE *q, char *pMem, int count)
|
||
+{
|
||
+ ARRIVE();
|
||
+ q->firstDescAddr = pMem;
|
||
+ q->lastDescAddr = (VIRT_ADDR)((UINT32)q->firstDescAddr +
|
||
+ (count - 1) * AE531X_QUEUE_ELE_SIZE);
|
||
+ q->curDescAddr = q->firstDescAddr;
|
||
+ q->count = count;
|
||
+ LEAVE();
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_TxQueueCreate - create a circular queue of descriptors for Transmit
|
||
+*/
|
||
+static int
|
||
+ae531x_TxQueueCreate(ae531x_MAC_t *MACInfo,
|
||
+ AE531X_QUEUE *q,
|
||
+ char *pMem,
|
||
+ int count)
|
||
+{
|
||
+ int i;
|
||
+ VIRT_ADDR descAddr;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ ae531x_QueueInit(q, pMem, count);
|
||
+ q->reapDescAddr = q->lastDescAddr;
|
||
+
|
||
+ /* Initialize Tx buffer descriptors. */
|
||
+ for (i=0, descAddr=q->firstDescAddr;
|
||
+ i<count;
|
||
+ i++, descAddr=(VIRT_ADDR)((UINT32)descAddr + AE531X_QUEUE_ELE_SIZE))
|
||
+ {
|
||
+ /* Update the size, BUFPTR, and SWPTR fields */
|
||
+
|
||
+ AE531X_DESC_STATUS_SET(descAddr, 0);
|
||
+ AE531X_DESC_CTRLEN_SET(descAddr, 0);
|
||
+
|
||
+ AE531X_DESC_BUFPTR_SET(descAddr, (UINT32)0);
|
||
+ AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0);
|
||
+ AE531X_DESC_SWPTR_SET(descAddr, (void *)0);
|
||
+ } /* for each desc */
|
||
+
|
||
+ /* Make the queue circular */
|
||
+ AE531X_DESC_CTRLEN_SET(q->lastDescAddr,
|
||
+ DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr));
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d Txbuf begin = %x, end = %x\n",
|
||
+ MACInfo->unit,
|
||
+ (UINT32)q->firstDescAddr,
|
||
+ (UINT32)q->lastDescAddr));
|
||
+
|
||
+ LEAVE();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_RxQueueCreate - create a circular queue of Rx descriptors
|
||
+*/
|
||
+int
|
||
+ae531x_RxQueueCreate(ae531x_MAC_t *MACInfo,
|
||
+ AE531X_QUEUE *q,
|
||
+ char *pMem,
|
||
+ int count)
|
||
+{
|
||
+ int i;
|
||
+ VIRT_ADDR descAddr;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ ae531x_QueueInit(q, pMem, count);
|
||
+ q->reapDescAddr = NULL;
|
||
+
|
||
+
|
||
+ /* Initialize Rx buffer descriptors */
|
||
+ for (i=0, descAddr=q->firstDescAddr;
|
||
+ i<count;
|
||
+ i++, descAddr=(VIRT_ADDR)((UINT32)descAddr + AE531X_QUEUE_ELE_SIZE))
|
||
+ {
|
||
+ void *swptr;
|
||
+ char *rxBuffer;
|
||
+ int rxBufferSize;
|
||
+
|
||
+ swptr = ae531x_rxbuf_alloc(MACInfo, &rxBuffer, &rxBufferSize);
|
||
+ if (swptr == NULL) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d RX queue: ae531x_rxbuf_alloc failed\n",
|
||
+ MACInfo->unit));
|
||
+ ae531x_QueueDestroy(q);
|
||
+ return -1;
|
||
+ }
|
||
+ AE531X_DESC_SWPTR_SET(descAddr, swptr);
|
||
+
|
||
+ AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma);
|
||
+ AE531X_DESC_CTRLEN_SET(descAddr, rxBufferSize);
|
||
+ AE531X_DESC_BUFPTR_SET(descAddr, virt_to_bus(rxBuffer));
|
||
+ AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0);
|
||
+ } /* for each desc */
|
||
+
|
||
+ /* Make the queue circular */
|
||
+ AE531X_DESC_CTRLEN_SET(q->lastDescAddr,
|
||
+ DescEndOfRing|AE531X_DESC_CTRLEN_GET(q->lastDescAddr));
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d Rxbuf begin = %x, end = %x\n",
|
||
+ MACInfo->unit,
|
||
+ (UINT32)q->firstDescAddr,
|
||
+ (UINT32)q->lastDescAddr));
|
||
+
|
||
+ LEAVE();
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_QueueDestroy -- Free all buffers and descriptors associated
|
||
+* with a queue.
|
||
+*/
|
||
+static void
|
||
+ae531x_QueueDestroy(AE531X_QUEUE *q)
|
||
+{
|
||
+ int i;
|
||
+ int count;
|
||
+ VIRT_ADDR descAddr;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ count = q->count;
|
||
+
|
||
+ for (i=0, descAddr=q->firstDescAddr;
|
||
+ i<count;
|
||
+ i++, descAddr=(VIRT_ADDR)((UINT32)descAddr + AE531X_QUEUE_ELE_SIZE)) {
|
||
+
|
||
+ AE531X_DESC_STATUS_SET(descAddr, 0);
|
||
+ AE531X_DESC_CTRLEN_SET(descAddr, 0);
|
||
+ AE531X_DESC_BUFPTR_SET(descAddr, (UINT32)0);
|
||
+ AE531X_DESC_LNKBUF_SET(descAddr, (UINT32)0);
|
||
+
|
||
+ ae531x_swptr_free(descAddr); /* Free OS-specific software pointer */
|
||
+ }
|
||
+
|
||
+ LEAVE();
|
||
+}
|
||
+
|
||
+static void
|
||
+ae531x_TxQueueDestroy(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_QueueDestroy(&MACInfo->txQueue);
|
||
+}
|
||
+
|
||
+static void
|
||
+ae531x_RxQueueDestroy(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_QueueDestroy(&MACInfo->rxQueue);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_AllocateQueues - Allocate receive and transmit queues
|
||
+*/
|
||
+int
|
||
+ae531x_AllocateQueues(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ size_t QMemSize;
|
||
+ char *pTxBuf = NULL;
|
||
+ char *pRxBuf = NULL;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ MACInfo->txDescCount = AE531X_TX_DESC_COUNT_DEFAULT;
|
||
+ QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->txDescCount;
|
||
+ pTxBuf = MALLOC(QMemSize);
|
||
+ if (pTxBuf == NULL) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d Failed to allocate TX queue\n", MACInfo->unit));
|
||
+ goto AllocQFail;
|
||
+ }
|
||
+
|
||
+ if (ae531x_TxQueueCreate(MACInfo, &MACInfo->txQueue, pTxBuf,
|
||
+ MACInfo->txDescCount) < 0)
|
||
+ {
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d Failed to create TX queue\n", MACInfo->unit));
|
||
+ goto AllocQFail;
|
||
+ }
|
||
+
|
||
+ MACInfo->rxDescCount = AE531X_RX_DESC_COUNT_DEFAULT;
|
||
+ QMemSize = AE531X_QUEUE_ELE_SIZE * MACInfo->rxDescCount;
|
||
+ pRxBuf = MALLOC(QMemSize);
|
||
+ if (pRxBuf == NULL) {
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d Failed to allocate RX queue\n", MACInfo->unit));
|
||
+ goto AllocQFail;
|
||
+ }
|
||
+
|
||
+ if (ae531x_RxQueueCreate(MACInfo, &MACInfo->rxQueue, pRxBuf,
|
||
+ MACInfo->rxDescCount) < 0)
|
||
+ {
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d Failed to create RX queue\n", MACInfo->unit));
|
||
+ goto AllocQFail;
|
||
+ }
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d Memory setup complete.\n", MACInfo->unit));
|
||
+
|
||
+ LEAVE();
|
||
+ return 0;
|
||
+
|
||
+AllocQFail:
|
||
+ MACInfo->txDescCount = 0; /* sanity */
|
||
+ MACInfo->rxDescCount = 0; /* sanity */
|
||
+
|
||
+ if (pTxBuf) {
|
||
+ FREE(pTxBuf);
|
||
+ }
|
||
+ if (pRxBuf) {
|
||
+ FREE(pRxBuf);
|
||
+ }
|
||
+
|
||
+ LEAVE();
|
||
+ return -1;
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_FreeQueues - Free Transmit & Receive queues
|
||
+*/
|
||
+void
|
||
+ae531x_FreeQueues(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_TxQueueDestroy(MACInfo);
|
||
+ FREE(MACInfo->txQueue.firstDescAddr);
|
||
+
|
||
+ ae531x_RxQueueDestroy(MACInfo);
|
||
+ FREE(MACInfo->rxQueue.firstDescAddr);
|
||
+}
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_DmaReset - Reset DMA and TLI controllers
|
||
+*
|
||
+* RETURNS: N/A
|
||
+*/
|
||
+void
|
||
+ae531x_DmaReset(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ int i;
|
||
+ UINT32 descAddr;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ /* Disable device interrupts prior to any errors during stop */
|
||
+ intDisable(MACInfo->ilevel);
|
||
+
|
||
+ /* Disable MAC rx and tx */
|
||
+ ae531x_ClearMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable));
|
||
+
|
||
+ /* Reset dma controller */
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaResetOn);
|
||
+
|
||
+ /* Delay 2 usec */
|
||
+ sysUDelay(2);
|
||
+
|
||
+ /* Flush the rx queue */
|
||
+ descAddr = (UINT32)MACInfo->rxQueue.firstDescAddr;
|
||
+ MACInfo->rxQueue.curDescAddr = MACInfo->rxQueue.firstDescAddr;
|
||
+ for (i=0;
|
||
+ i<(MACInfo->rxDescCount);
|
||
+ i++, descAddr += AE531X_QUEUE_ELE_SIZE) {
|
||
+ AE531X_DESC_STATUS_SET(descAddr, DescOwnByDma);
|
||
+ }
|
||
+
|
||
+ /* Flush the tx queue */
|
||
+ descAddr = (UINT32)MACInfo->txQueue.firstDescAddr;
|
||
+ MACInfo->txQueue.curDescAddr = MACInfo->txQueue.firstDescAddr;
|
||
+ MACInfo->txQueue.reapDescAddr = MACInfo->txQueue.lastDescAddr;
|
||
+ for (i=0;
|
||
+ i<(MACInfo->txDescCount);
|
||
+ i++, descAddr += AE531X_QUEUE_ELE_SIZE) {
|
||
+ AE531X_DESC_STATUS_SET (descAddr, 0);
|
||
+ }
|
||
+
|
||
+ /* Set init register values */
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaBusMode, DmaBusModeInit);
|
||
+
|
||
+ /* Install the first Tx and Rx queues on the device */
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaRxBaseAddr,
|
||
+ (UINT32)MACInfo->rxQueue.firstDescAddr);
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaTxBaseAddr,
|
||
+ (UINT32)MACInfo->txQueue.firstDescAddr);
|
||
+
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaControl, DmaStoreAndForward);
|
||
+
|
||
+ ae531x_WriteDmaReg(MACInfo, DmaIntrEnb, DmaIntDisable);
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d: DMA RESET!\n", MACInfo->unit));
|
||
+
|
||
+ /* Turn on device interrupts -- enable most errors */
|
||
+ ae531x_DmaIntClear(MACInfo); /* clear interrupt requests */
|
||
+ ae531x_DmaIntEnable(MACInfo); /* enable interrupts */
|
||
+ /* Enable receive interrupts separately (they are not part
|
||
+ * of the main group since they are enabled & disabled by
|
||
+ * the polling routine.
|
||
+ */
|
||
+ ae531x_SetDmaReg(MACInfo, DmaIntrEnb,
|
||
+ (DmaIntRxNoBuffer | DmaIntRxCompleted));
|
||
+
|
||
+ ae531x_EndResetMode(MACInfo);
|
||
+
|
||
+ intEnable(MACInfo->ilevel);
|
||
+
|
||
+ LEAVE();
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae531x_MACAddressSet - Set the ethernet address
|
||
+*
|
||
+* Sets the ethernet address according to settings in flash.
|
||
+*
|
||
+* RETURNS: void
|
||
+*/
|
||
+static void
|
||
+ae531x_MACAddressSet(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ unsigned int data;
|
||
+ UINT8 *macAddr;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ macAddr = macAddrGet(MACInfo);
|
||
+
|
||
+ /* set our MAC address */
|
||
+ data = (macAddr[5]<<8) | macAddr[4];
|
||
+ ae531x_WriteMacReg(MACInfo, MacAddrHigh, data );
|
||
+
|
||
+ data = (macAddr[3]<<24) | (macAddr[2]<<16) | (macAddr[1]<<8) | macAddr[0];
|
||
+ ae531x_WriteMacReg(MACInfo, MacAddrLow, data );
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ ("ethmac%d Verify MAC address %8.8X %8.8X \n",
|
||
+ MACInfo->unit,
|
||
+ ae531x_ReadMacReg(MACInfo, MacAddrLow),
|
||
+ ae531x_ReadMacReg(MACInfo, MacAddrHigh)));
|
||
+
|
||
+ AE531X_PRINT(AE531X_DEBUG_RESET,
|
||
+ (" sb = %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
|
||
+ 0xff&macAddr[0],
|
||
+ 0xff&macAddr[1],
|
||
+ 0xff&macAddr[2],
|
||
+ 0xff&macAddr[3],
|
||
+ 0xff&macAddr[4],
|
||
+ 0xff&macAddr[5]));
|
||
+ LEAVE();
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* ae_SetMACFromPhy - read Phy settings and update Mac
|
||
+* with current duplex and speed.
|
||
+*
|
||
+* RETURNS:
|
||
+*/
|
||
+static void
|
||
+ae531x_SetMACFromPhy(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ UINT32 macCtl;
|
||
+ BOOL fullDuplex;
|
||
+
|
||
+ ARRIVE();
|
||
+
|
||
+ /* Get duplex mode from Phy */
|
||
+ fullDuplex = phyIsFullDuplex(MACInfo->unit);
|
||
+
|
||
+ /* Flag is set for full duplex mode, else cleared */
|
||
+ macCtl = ae531x_ReadMacReg(MACInfo, MacControl);
|
||
+
|
||
+ if (fullDuplex) {
|
||
+ /* set values of control registers */
|
||
+ macCtl &= ~MacDisableRxOwn;
|
||
+ macCtl |= MacFullDuplex;
|
||
+ ae531x_WriteMacReg(MACInfo, MacControl, macCtl);
|
||
+ ae531x_WriteMacReg(MACInfo, MacFlowControl, MacFlowControlInitFdx);
|
||
+#if 0
|
||
+ printk ("[Full Duplex] CTRL=%#x FLOW=%#x\n", macCtl,
|
||
+ MacFlowControlInitFdx);
|
||
+#endif
|
||
+ } else {
|
||
+ /* set values of control registers */
|
||
+ ae531x_WriteMacReg(MACInfo, MacFlowControl, MacFlowControlInitHdx);
|
||
+ macCtl |= MacDisableRxOwn;
|
||
+ macCtl &= ~MacFullDuplex;
|
||
+ ae531x_WriteMacReg(MACInfo, MacControl, macCtl);
|
||
+#if 0
|
||
+ printk ("[Half Duplex] CTRL=%#x FLOW=%#x\n", macCtl,
|
||
+ MacFlowControlInitHdx);
|
||
+#endif
|
||
+ }
|
||
+
|
||
+ LEAVE();
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_MACReset -- sets MAC address and duplex.
|
||
+*/
|
||
+void
|
||
+ae531x_MACReset(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_MACAddressSet(MACInfo);
|
||
+
|
||
+ ae531x_SetMACFromPhy(MACInfo);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_EnableComm -- enable Transmit and Receive
|
||
+*/
|
||
+void
|
||
+ae531x_EnableComm(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_SetMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable));
|
||
+ ae531x_DmaRxStart(MACInfo); /* start receiver */
|
||
+ ae531x_DmaTxStart(MACInfo); /* start transmitter */
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_DisableComm -- disable Transmit and Receive
|
||
+*/
|
||
+void
|
||
+ae531x_DisableComm(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ ae531x_ClearMacReg(MACInfo, MacControl, (MacRxEnable | MacTxEnable));
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_reset -- Cold reset ethernet interface
|
||
+*/
|
||
+void
|
||
+ae531x_reset(ae531x_MAC_t *MACInfo)
|
||
+{
|
||
+ UINT32 mask = 0;
|
||
+ UINT32 regtmp;
|
||
+
|
||
+ if (ar531x_num_enet_macs == 2) {
|
||
+ if (MACInfo->unit == 0) {
|
||
+ mask = AR531X_RESET_ENET0 | AR531X_RESET_EPHY0;
|
||
+ } else {
|
||
+ mask = AR531X_RESET_ENET1 | AR531X_RESET_EPHY1;
|
||
+ }
|
||
+ } else {
|
||
+ mask = AR531X_RESET_ENET0 | AR531X_RESET_EPHY0 |
|
||
+ AR531X_RESET_ENET1 | AR531X_RESET_EPHY1;
|
||
+ }
|
||
+
|
||
+ /* Put into reset */
|
||
+ regtmp = sysRegRead(AR531X_RESET);
|
||
+ sysRegWrite(AR531X_RESET, regtmp | mask);
|
||
+ sysMsDelay(15);
|
||
+
|
||
+ /* Pull out of reset */
|
||
+ regtmp = sysRegRead(AR531X_RESET);
|
||
+ sysRegWrite(AR531X_RESET, regtmp & ~mask);
|
||
+ sysUDelay(25);
|
||
+
|
||
+ /* Enable */
|
||
+ if (ar531x_num_enet_macs == 2) {
|
||
+ if (MACInfo->unit == 0) {
|
||
+ mask = AR531X_ENABLE_ENET0;
|
||
+ } else {
|
||
+ mask = AR531X_ENABLE_ENET1;
|
||
+ }
|
||
+ } else {
|
||
+ mask = AR531X_ENABLE_ENET0 | AR531X_ENABLE_ENET1;
|
||
+ }
|
||
+ regtmp = sysRegRead(AR531X_ENABLE);
|
||
+ sysRegWrite(AR531X_ENABLE, regtmp | mask);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_unitLinkLost -- Called from PHY layer to notify the MAC layer
|
||
+* that there are no longer any live links associated with a MAC.
|
||
+*/
|
||
+void
|
||
+ae531x_unitLinkLost(int ethUnit)
|
||
+{
|
||
+ AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE,
|
||
+ ("enetmac%d link down\n", ethUnit));
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_unitLinkGained -- Called from PHY layer to notify the MAC layer
|
||
+* that there are 1 or more live links associated with a MAC.
|
||
+*/
|
||
+void
|
||
+ae531x_unitLinkGained(int ethUnit)
|
||
+{
|
||
+ AE531X_PRINT(AE531X_DEBUG_LINK_CHANGE,
|
||
+ ("enet%d link up\n", ethUnit));
|
||
+}
|
||
+
|
||
+/******************************************************************************
|
||
+* ae531x_ethMacDefault -- Called from PHY layer to determine the default
|
||
+* ethernet MAC. On some "twisted" platforms, the only usable MAC is 1,
|
||
+* while on others the usable MAC is 0. Future boards may allow both MACs
|
||
+* to be used; in this case, return -1 to indicate that there IS NO default
|
||
+* MAC.
|
||
+*
|
||
+* Note: one some AR2312 platforms the PHY needs to be accessed through
|
||
+* MAC 0, even though the MAC itself is addressed through MAC 1. Since this
|
||
+* function is used by the PHY layer to determine which MAC it should use,
|
||
+* the twisted case is limited to the one where the PHY is actually addressed
|
||
+* through MAC 1 rather than MAC 0.
|
||
+*/
|
||
+int
|
||
+ae531x_ethMacDefault(void)
|
||
+{
|
||
+ /*
|
||
+ * Where there are two MACs, there is no real default
|
||
+ */
|
||
+ if (ar531x_num_enet_macs == 2)
|
||
+ return -1;
|
||
+
|
||
+ /*
|
||
+ * All single MAC platforms seem to address the PHY through MAC 0,
|
||
+ * even when they use MAC 1 for the actual MAC functions.
|
||
+ */
|
||
+ return 0;
|
||
+}
|
||
diff -urN linux-2.4.32.new/arch/mips/ar531x/ae531xmac.h linux-2.4.32.new-eth/arch/mips/ar531x/ae531xmac.h
|
||
--- linux-2.4.32.new/arch/mips/ar531x/ae531xmac.h 1970-01-01 01:00:00.000000000 +0100
|
||
+++ linux-2.4.32.new-eth/arch/mips/ar531x/ae531xmac.h 2005-12-25 11:54:20.819264376 +0000
|
||
@@ -0,0 +1,208 @@
|
||
+/*
|
||
+ * This file is subject to the terms and conditions of the GNU General Public
|
||
+ * License. See the file "COPYING" in the main directory of this archive
|
||
+ * for more details.
|
||
+ *
|
||
+ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
|
||
+ */
|
||
+
|
||
+/*
|
||
+ * See README to understand the decomposition of the ethernet driver.
|
||
+ *
|
||
+ * This file contains OS-independent pure software definitions for
|
||
+ * ethernet support on the AR531X platform.
|
||
+ */
|
||
+
|
||
+#ifndef _AE531XMAC_H_
|
||
+#define _AE531XMAC_H_
|
||
+
|
||
+/*
|
||
+ * DEBUG switches to control verbosity.
|
||
+ * Just modify the value of ae531x_MAC_debug.
|
||
+ */
|
||
+#define AE531X_DEBUG_ALL 0xffffffff
|
||
+#define AE531X_DEBUG_ERROR 0x00000001 /* Unusual conditions and Errors */
|
||
+#define AE531X_DEBUG_ARRIVE 0x00000002 /* Arrive into a function */
|
||
+#define AE531X_DEBUG_LEAVE 0x00000004 /* Leave a function */
|
||
+#define AE531X_DEBUG_RESET 0x00000008 /* Reset */
|
||
+#define AE531X_DEBUG_TX 0x00000010 /* Transmit */
|
||
+#define AE531X_DEBUG_TX_REAP 0x00000020 /* Transmit Descriptor Reaping */
|
||
+#define AE531X_DEBUG_RX 0x00000040 /* Receive */
|
||
+#define AE531X_DEBUG_RX_STOP 0x00000080 /* Receive Early Stop */
|
||
+#define AE531X_DEBUG_INT 0x00000100 /* Interrupts */
|
||
+#define AE531X_DEBUG_LINK_CHANGE 0x00000200 /* PHY Link status changed */
|
||
+
|
||
+extern int ae531x_MAC_debug;
|
||
+
|
||
+extern int ar531x_num_enet_macs;
|
||
+
|
||
+#define AE531X_PRINT(FLG, X) \
|
||
+{ \
|
||
+ if (ae531x_MAC_debug & (FLG)) { \
|
||
+ DEBUG_PRINTF("%s#%d:%s ", \
|
||
+ __FILE__, \
|
||
+ __LINE__, \
|
||
+ __FUNCTION__); \
|
||
+ DEBUG_PRINTF X; \
|
||
+ } \
|
||
+}
|
||
+
|
||
+#define ARRIVE() AE531X_PRINT(AE531X_DEBUG_ARRIVE, ("Arrive{\n"))
|
||
+#define LEAVE() AE531X_PRINT(AE531X_DEBUG_LEAVE, ("}Leave\n"))
|
||
+
|
||
+#define RegRead(addr) \
|
||
+ (*(volatile unsigned int *)(addr))
|
||
+
|
||
+#define RegWrite(val,addr) \
|
||
+ ((*(volatile unsigned int *)(addr)) = (val))
|
||
+
|
||
+/*****************************************************************
|
||
+ * Phy code is broken out into a separate layer, so that different
|
||
+ * PHY hardware can easily be supported.
|
||
+ *
|
||
+ * These functions are provided by the PHY layer for use by the MAC layer.
|
||
+ * phySetup -- Set phy hardware appropriately for a MAC unit
|
||
+ *
|
||
+ * phyCheckStatusChange -- Look for dropped/initiated links on any
|
||
+ * phy port associated with a MAC unit
|
||
+ *
|
||
+ * phyIsSpeed100 -- Determines whether or not a PHY is up and
|
||
+ * running at 100Mbit
|
||
+ *
|
||
+ * phyIsFullDuplex -- Determines whether or not a PHY is up and
|
||
+ * running in Full Duplex mode
|
||
+ *
|
||
+ */
|
||
+#ifdef CONFIG_MARVELL_ENET_PHY
|
||
+/*
|
||
+ * Mapping of generic phy APIs to Marvell Ethernet Switch phy functions.
|
||
+ */
|
||
+#include "mvPhy.h"
|
||
+#define phySetup(ethUnit, phyBase) mv_phySetup((ethUnit), (phyBase))
|
||
+#define phyCheckStatusChange(ethUnit) mv_phyCheckStatusChange(ethUnit)
|
||
+#define phyIsSpeed100(ethUnit) mv_phyIsSpeed100(ethUnit)
|
||
+#define phyIsFullDuplex(ethUnit) mv_phyIsFullDuplex(ethUnit)
|
||
+
|
||
+#ifdef CONFIG_VENETDEV
|
||
+#define PHY_TRAILER_SIZE MV_PHY_TRAILER_SIZE
|
||
+extern int mv_phyDetermineSource(char *data, int len);
|
||
+extern void mv_phySetDestinationPort(char *data, int len, int fromLAN);
|
||
+#define phyDetermineSource(data, len) mv_phyDetermineSource((data), (len))
|
||
+#define phySetDestinationPort(data, len, fromLAN) mv_phySetDestinationPort((data), (len), (fromLAN))
|
||
+#else
|
||
+#define PHY_TRAILER_SIZE 0
|
||
+#endif
|
||
+#endif /* CONFIG_MARVELL_ENET_PHY */
|
||
+
|
||
+#if defined(CONFIG_KENDIN_ENET_PHY) || defined(CONFIG_REALTEK_ENET_PHY)
|
||
+/*
|
||
+ * Mapping of generic phy APIs to Kendin KS8721B and RealTek RTL8201BL phys.
|
||
+ */
|
||
+#include "rtPhy.h"
|
||
+#define phySetup(ethUnit, phyBase) rt_phySetup((ethUnit), (phyBase))
|
||
+#define phyCheckStatusChange(ethUnit) rt_phyCheckStatusChange(ethUnit)
|
||
+#define phyIsSpeed100(ethUnit) rt_phyIsSpeed100(ethUnit)
|
||
+#define phyIsFullDuplex(ethUnit) rt_phyIsFullDuplex(ethUnit)
|
||
+#endif
|
||
+
|
||
+#if !defined(PHY_TRAILER_SIZE)
|
||
+#define PHY_TRAILER_SIZE 0
|
||
+#endif
|
||
+
|
||
+/*****************************************************************
|
||
+ * MAC-independent interface to be used by PHY code
|
||
+ *
|
||
+ * These functions are provided by the MAC layer for use by the PHY layer.
|
||
+ */
|
||
+#define phyRegRead ae531x_MiiRead
|
||
+#define phyRegWrite ae531x_MiiWrite
|
||
+#define phyLinkLost(ethUnit) ae531x_unitLinkLost(ethUnit)
|
||
+#define phyLinkGained(ethUnit) ae531x_unitLinkGained(ethUnit)
|
||
+#define phyEthMacDefault() ae531x_ethMacDefault()
|
||
+
|
||
+void ae531x_unitLinkLost(int unit);
|
||
+void ae531x_unitLinkGained(int unit);
|
||
+int ae531x_ethMacDefault(void);
|
||
+
|
||
+
|
||
+/* RXBUFF_RESERVE enables building header on WLAN-side in place */
|
||
+#define RXBUFF_RESERVE 96
|
||
+#define ETH_CRC_LEN 4
|
||
+
|
||
+/*****************************************************************
|
||
+ * Descriptor queue
|
||
+ */
|
||
+typedef struct ae531x_queue {
|
||
+ VIRT_ADDR firstDescAddr; /* descriptor array address */
|
||
+ VIRT_ADDR lastDescAddr; /* last descriptor address */
|
||
+ VIRT_ADDR curDescAddr; /* current descriptor address */
|
||
+ VIRT_ADDR reapDescAddr; /* current tail of tx descriptors reaped */
|
||
+ UINT16 count; /* number of elements */
|
||
+} AE531X_QUEUE;
|
||
+
|
||
+/* Given a descriptor, return the next one in a circular list */
|
||
+#define AE531X_QUEUE_ELE_NEXT_GET(q, descAddr) \
|
||
+ ((descAddr) == (q)->lastDescAddr) ? (q)->firstDescAddr : \
|
||
+ (VIRT_ADDR)((UINT32)(descAddr) + AE531X_QUEUE_ELE_SIZE)
|
||
+
|
||
+/* Move the "current descriptor" forward to the next one */
|
||
+#define AE531X_CONSUME_DESC(q) \
|
||
+ q->curDescAddr = AE531X_QUEUE_ELE_NEXT_GET(q, q->curDescAddr)
|
||
+
|
||
+/*****************************************************************
|
||
+ * Per-ethernet-MAC OS-independent information
|
||
+ */
|
||
+typedef struct ae531x_MAC_s {
|
||
+ u32 unit; /* MAC unit ID */
|
||
+ u32 macBase; /* MAC base address */
|
||
+ u32 dmaBase; /* DMA base address */
|
||
+ u32 phyBase; /* PHY base address */
|
||
+ AE531X_QUEUE txQueue; /* Transmit descriptor queue */
|
||
+ AE531X_QUEUE rxQueue; /* Receive descriptor queue */
|
||
+ UINT16 txDescCount; /* Transmit descriptor count */
|
||
+ UINT16 rxDescCount; /* Receive descriptor count */
|
||
+ BOOL aeProcessRst; /* flag to indicate reset in progress */
|
||
+ BOOL port_is_up; /* flag to indicate port is up */
|
||
+ void *OSinfo; /* OS-dependent data */
|
||
+} ae531x_MAC_t;
|
||
+
|
||
+#define AE531X_TX_DESC_COUNT_DEFAULT 64 /* Transmit descriptors */
|
||
+#define AE531X_RX_DESC_COUNT_DEFAULT 64 /* Receive descriptors */
|
||
+
|
||
+
|
||
+/*****************************************************************
|
||
+ * Interfaces exported by the OS-independent MAC layer
|
||
+ */
|
||
+void ae531x_BeginResetMode(ae531x_MAC_t *MACInfo);
|
||
+void ae531x_EndResetMode(ae531x_MAC_t *MACInfo);
|
||
+BOOL ae531x_IsInResetMode(ae531x_MAC_t *MACInfo);
|
||
+int ae531x_RxQueueCreate(ae531x_MAC_t *MACInfo, AE531X_QUEUE *q,
|
||
+ char *pMem, int count);
|
||
+int ae531x_QueueDelete(struct ae531x_queue *q);
|
||
+void ae531x_DmaReset(ae531x_MAC_t *MACInfo);
|
||
+void ae531x_MACReset(ae531x_MAC_t *MACInfo);
|
||
+void ae531x_EnableComm(ae531x_MAC_t *MACInfo);
|
||
+void ae531x_DisableComm(ae531x_MAC_t *MACInfo);
|
||
+void ae531x_reset(ae531x_MAC_t *MACInfo);
|
||
+int ae531x_AllocateQueues(ae531x_MAC_t *MACInfo);
|
||
+void ae531x_FreeQueues(ae531x_MAC_t *MACInfo);
|
||
+void ae531x_QueueInit(AE531X_QUEUE *q, char *pMem, int count);
|
||
+UINT32 ae531x_ReadMacReg(ae531x_MAC_t *MACInfo, UINT32 reg);
|
||
+void ae531x_WriteMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data);
|
||
+void ae531x_SetMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
|
||
+void ae531x_ClearMacReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
|
||
+void ae531x_SetDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
|
||
+void ae531x_ClearDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 val);
|
||
+UINT32 ae531x_ReadDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg);
|
||
+void ae531x_WriteDmaReg(ae531x_MAC_t *MACInfo, UINT32 reg, UINT32 data);
|
||
+UINT32 ae531x_ReadMiiReg(UINT32 phyBase, UINT32 reg);
|
||
+void ae531x_WriteMiiReg(UINT32 phyBase, UINT32 reg, UINT32 data);
|
||
+UINT16 ae531x_MiiRead(UINT32 phyBase, UINT32 phyAddr, UINT8 reg);
|
||
+void ae531x_MiiWrite(UINT32 phyBase, UINT32 phyAddr, UINT8 reg, UINT16 data);
|
||
+void ae531x_DmaIntEnable(ae531x_MAC_t *MACInfo);
|
||
+void ae531x_DmaIntDisable(ae531x_MAC_t *MACInfo);
|
||
+void ae531x_AckIntr(ae531x_MAC_t *MACInfo, UINT32 val);
|
||
+void *ae531x_rxbuf_alloc(ae531x_MAC_t *MACInfo, char **rxBptr, int *rxBSize);
|
||
+void ae531x_swptr_free(VIRT_ADDR txDesc);
|
||
+
|
||
+#endif /* _AE531XMAC_H_ */
|
||
diff -urN linux-2.4.32.new/arch/mips/ar531x/ae531xreg.h linux-2.4.32.new-eth/arch/mips/ar531x/ae531xreg.h
|
||
--- linux-2.4.32.new/arch/mips/ar531x/ae531xreg.h 1970-01-01 01:00:00.000000000 +0100
|
||
+++ linux-2.4.32.new-eth/arch/mips/ar531x/ae531xreg.h 2005-12-25 11:54:20.834262096 +0000
|
||
@@ -0,0 +1,437 @@
|
||
+/*
|
||
+ * This file is subject to the terms and conditions of the GNU General Public
|
||
+ * License. See the file "COPYING" in the main directory of this archive
|
||
+ * for more details.
|
||
+ *
|
||
+ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
|
||
+ */
|
||
+
|
||
+/*
|
||
+ * See README to understand the decomposition of the ethernet driver.
|
||
+ *
|
||
+ * Register definitions for Atheros AR531X Ethernet MAC.
|
||
+ */
|
||
+
|
||
+#ifndef _AE531XREG_H_
|
||
+#define _AE531XREG_H_
|
||
+
|
||
+#define AE531X_MAC_OFFSET 0x0000
|
||
+#define AE531X_PHY_OFFSET 0x0000 /* Same as MAC offset */
|
||
+#define AE531X_DMA_OFFSET 0x1000
|
||
+
|
||
+/***********************************************************/
|
||
+/* MAC110 registers, base address is BAR+AE531X_MAC_OFFSET */
|
||
+/***********************************************************/
|
||
+#define MacControl 0x00 /* control */
|
||
+#define MacAddrHigh 0x04 /* address high */
|
||
+#define MacAddrLow 0x08 /* address low */
|
||
+#define MacMultiHashHigh 0x0C /* multicast hash table high */
|
||
+#define MacMultiHashLow 0x10 /* multicast hash table low */
|
||
+#define MacMiiAddr 0x14 /* MII address */
|
||
+#define MacMiiData 0x18 /* MII data */
|
||
+#define MacFlowControl 0x1C /* Flow control */
|
||
+#define MacVlan1Tag 0x4C /* VLAN1 tag */
|
||
+#define MacVlan2Tag 0x50 /* VLAN2 tag */
|
||
+
|
||
+
|
||
+/***************************************************************/
|
||
+/* DMA engine registers, base address is BAR+AE531X_DMA_OFFSET */
|
||
+/***************************************************************/
|
||
+#define DmaBusMode 0x00 /* CSR0 - Bus Mode */
|
||
+#define DmaTxPollDemand 0x04 /* CSR1 - Transmit Poll Demand */
|
||
+#define DmaRxPollDemand 0x08 /* CSR2 - Receive Poll Demand */
|
||
+#define DmaRxBaseAddr 0x0C /* CSR3 - Receive list base address */
|
||
+#define DmaTxBaseAddr 0x10 /* CSR4 - Transmit list base address */
|
||
+#define DmaStatus 0x14 /* CSR5 - Dma status */
|
||
+#define DmaControl 0x18 /* CSR6 - Dma control */
|
||
+#define DmaIntrEnb 0x1C /* CSR7 - Interrupt enable */
|
||
+#define DmaOverflowCnt 0x20 /* CSR8 - Missed Frame and Buff Overflow counter */
|
||
+#define DmaTxCurrAddr 0x50 /* CSR20 - Current host transmit buffer address */
|
||
+#define DmaRxCurrAddr 0x54 /* CSR21 - Current host receive buffer address */
|
||
+
|
||
+/**********************************************************/
|
||
+/* MAC Control register layout */
|
||
+/**********************************************************/
|
||
+#define MacFilterOff 0x80000000 /* Receive all incoming packets RW */
|
||
+#define MacFilterOn 0 /* Receive filtered packets only 0 */
|
||
+#define MacBigEndian 0x40000000 /* Big endian mode RW */
|
||
+#define MacLittleEndian 0 /* Little endian 0 */
|
||
+#define MacHeartBeatOff 0x10000000 /* Heartbeat signal qual disable RW*/
|
||
+#define MacHeartBeatOn 0 /* Heartbeat signal qual enable 0 */
|
||
+#define MacSelectSrl 0x08000000 /* Select SRL port RW */
|
||
+#define MacSelectMii 0 /* Select MII port 0 */
|
||
+#define MacDisableRxOwn 0x00800000 /* Disable receive own packets RW */
|
||
+#define MacEnableRxOwn 0 /* Enable receive own packets 0 */
|
||
+#define MacLoopbackExt 0x00400000 /* External loopback RW */
|
||
+#define MacLoopbackInt 0x00200000 /* Internal loopback */
|
||
+#define MacLoopbackOff 0 /* Normal mode 00 */
|
||
+#define MacFullDuplex 0x00100000 /* Full duplex mode RW */
|
||
+#define MacHalfDuplex 0 /* Half duplex mode 0 */
|
||
+#define MacMulticastFilterOff 0x00080000 /* Pass all multicast packets RW */
|
||
+#define MacMulticastFilterOn 0 /* Pass filtered mcast packets 0 */
|
||
+#define MacPromiscuousModeOn 0x00040000 /* Receive all valid packets RW 1 */
|
||
+#define MacPromiscuousModeOff 0 /* Receive filtered packets only */
|
||
+#define MacFilterInverse 0x00020000 /* Inverse filtering RW */
|
||
+#define MacFilterNormal 0 /* Normal filtering 0 */
|
||
+#define MacBadFramesEnable 0x00010000 /* Pass bad frames RW */
|
||
+#define MacBadFramesDisable 0 /* Do not pass bad frames 0 */
|
||
+#define MacPerfectFilterOff 0x00008000 /* Hash filtering only RW */
|
||
+#define MacPerfectFilterOn 0 /* Both perfect and hash filtering 0 */
|
||
+#define MacHashFilterOn 0x00002000 /* perform hash filtering RW */
|
||
+#define MacHashFilterOff 0 /* perfect filtering only 0 */
|
||
+#define MacLateCollisionOn 0x00001000 /* Enable late collision control RW */
|
||
+#define MacLateCollisionOff 0 /* Disable late collision control 0 */
|
||
+#define MacBroadcastDisable 0x00000800 /* Disable reception of bcast frames RW */
|
||
+#define MacBroadcastEnable 0 /* Enable broadcast frames 0 */
|
||
+#define MacRetryDisable 0x00000400 /* Disable retransmission RW */
|
||
+#define MacRetryEnable 0 /* Enable retransmission 0 */
|
||
+#define MacPadStripEnable 0x00000100 /* Pad stripping enable RW */
|
||
+#define MacPadStripDisable 0 /* Pad stripping disable 0 */
|
||
+#define MacBackoff 0 /* Backoff Limit RW 00 */
|
||
+#define MacDeferralCheckEnable 0x00000020 /* Deferral check enable RW */
|
||
+#define MacDeferralCheckDisable 0 /* Deferral check disable 0 */
|
||
+#define MacTxEnable 0x00000008 /* Transmitter enable RW */
|
||
+#define MacTxDisable 0 /* Transmitter disable 0 */
|
||
+#define MacRxEnable 0x00000004 /* Receiver enable RW */
|
||
+#define MacRxDisable 0 /* Receiver disable 0 */
|
||
+
|
||
+
|
||
+/**********************************************************/
|
||
+/* MII address register layout */
|
||
+/**********************************************************/
|
||
+#define MiiDevMask 0x0000F800 /* MII device address */
|
||
+#define MiiDevShift 11
|
||
+#define MiiRegMask 0x000007C0 /* MII register */
|
||
+#define MiiRegShift 6
|
||
+#define MiiWrite 0x00000002 /* Write to register */
|
||
+#define MiiRead 0 /* Read from register */
|
||
+#define MiiBusy 0x00000001 /* MII interface is busy */
|
||
+
|
||
+/**********************************************************/
|
||
+/* MII Data register layout */
|
||
+/**********************************************************/
|
||
+#define MiiDataMask 0x0000FFFF /* MII Data */
|
||
+
|
||
+/**********************************************************/
|
||
+/* MAC flow control register layout */
|
||
+/**********************************************************/
|
||
+#define MacPauseTimeMask 0xFFFF0000 /* PAUSE TIME field in ctrl frame */
|
||
+#define MacPauseTimeShift 15
|
||
+#define MacControlFrameEnable 0x00000004 /* Enable pass ctrl frames to host */
|
||
+#define MacControlFrameDisable 0 /* Do not pass ctrl frames to host */
|
||
+#define MacFlowControlEnable 0x00000002 /* Enable flow control */
|
||
+#define MacFlowControlDisable 0 /* Disable flow control */
|
||
+#define MacSendPauseFrame 0x00000001 /* send pause frame */
|
||
+
|
||
+/**********************************************************/
|
||
+/* DMA bus mode register layout */
|
||
+/**********************************************************/
|
||
+#define DmaRxAlign16 0x01000000 /* Force all rx buffers to align on odd hw bndry */
|
||
+#define DmaBigEndianDes 0x00100000 /* Big endian data buffer descriptors RW */
|
||
+#define DmaLittleEndianDesc 0 /* Little endian data descriptors */
|
||
+#define DmaBurstLength32 0x00002000 /* Dma burst length 32 RW */
|
||
+#define DmaBurstLength16 0x00001000 /* Dma burst length 16 */
|
||
+#define DmaBurstLength8 0x00000800 /* Dma burst length 8 */
|
||
+#define DmaBurstLength4 0x00000400 /* Dma burst length 4 */
|
||
+#define DmaBurstLength2 0x00000200 /* Dma burst length 2 */
|
||
+#define DmaBurstLength1 0x00000100 /* Dma burst length 1 */
|
||
+#define DmaBurstLength0 0x00000000 /* Dma burst length 0 */
|
||
+#define DmaBigEndianData 0x00000080 /* Big endian data buffers RW */
|
||
+#define DmaLittleEndianData 0 /* Little endian data buffers 0 */
|
||
+#define DmaDescriptorSkip16 0x00000040 /* number of dwords to skip RW */
|
||
+#define DmaDescriptorSkip8 0x00000020 /* between two unchained descriptors */
|
||
+#define DmaDescriptorSkip4 0x00000010
|
||
+#define DmaDescriptorSkip2 0x00000008
|
||
+#define DmaDescriptorSkip1 0x00000004
|
||
+#define DmaDescriptorSkip0 0
|
||
+#define DmaReceivePriorityOff 0x00000002 /* equal rx and tx priorities RW */
|
||
+#define DmaReceivePriorityOn 0 /* Rx has prioryty over Tx 0 */
|
||
+#define DmaResetOn 0x00000001 /* Reset DMA engine RW */
|
||
+#define DmaResetOff 0
|
||
+
|
||
+/**********************************************************/
|
||
+/* DMA Status register layout */
|
||
+/**********************************************************/
|
||
+#define DmaRxAbort 0x01000000 /* receiver bus abort R 0 */
|
||
+#define DmaTxAbort 0x00800000 /* transmitter bus abort R 0 */
|
||
+#define DmaTxState 0x00700000 /* Transmit process state R 000 */
|
||
+#define DmaTxStopped 0x00000000 /* Stopped */
|
||
+#define DmaTxFetching 0x00100000 /* Running - fetching the descriptor */
|
||
+#define DmaTxWaiting 0x00200000 /* Running - waiting for end of transmission */
|
||
+#define DmaTxReading 0x00300000 /* Running - reading the data from memory */
|
||
+#define DmaTxSuspended 0x00600000 /* Suspended */
|
||
+#define DmaTxClosing 0x00700000 /* Running - closing descriptor */
|
||
+#define DmaRxState 0x000E0000 /* Receive process state 000 */
|
||
+#define DmaRxStopped 0x00000000 /* Stopped */
|
||
+#define DmaRxFetching 0x00020000 /* Running - fetching the descriptor */
|
||
+#define DmaRxChecking 0x00040000 /* Running - checking for end of packet */
|
||
+#define DmaRxWaiting 0x00060000 /* Running - waiting for packet */
|
||
+#define DmaRxSuspended 0x00080000 /* Suspended */
|
||
+#define DmaRxClosing 0x000A0000 /* Running - closing descriptor */
|
||
+#define DmaRxFlushing 0x000C0000 /* Running - flushing the current frame */
|
||
+#define DmaRxQueuing 0x000E0000 /* Running - queuing the recieve frame into host memory */
|
||
+#define DmaIntNormal 0x00010000 /* Normal interrupt summary RW 0 */
|
||
+#define DmaIntAbnormal 0x00008000 /* Abnormal interrupt summary RW 0 */
|
||
+#define DmaIntEarlyRx 0x00004000 /* Early receive interrupt (Normal) RW 0 */
|
||
+#define DmaIntBusError 0x00002000 /* Fatal bus error (Abnormal) RW 0 */
|
||
+#define DmaIntEarlyTx 0x00000400 /* Early transmit interrupt RW 0 */
|
||
+#define DmaIntRxStopped 0x00000100 /* Receive process stopped (Abnormal) RW 0 */
|
||
+#define DmaIntRxNoBuffer 0x00000080 /* Receive buffer unavailable (Abnormal) RW 0*/
|
||
+#define DmaIntRxCompleted 0x00000040 /* Completion of frame reception(Normal) RW 0*/
|
||
+#define DmaIntTxUnderflow 0x00000020 /* Transmit underflow (Abnormal) RW 0 */
|
||
+#define DmaIntTxJabber 0x00000008 /* Transmit Jabber Timeout (Abnormal) RW 0 */
|
||
+#define DmaIntTxNoBuffer 0x00000004 /* Transmit buffer unavailable (Normal) RW 0*/
|
||
+#define DmaIntTxStopped 0x00000002 /* Transmit process stopped (Abnormal) RW 0 */
|
||
+#define DmaIntTxCompleted 0x00000001 /* Transmit completed (Normal) RW 0 */
|
||
+
|
||
+/**********************************************************/
|
||
+/* DMA control register layout */
|
||
+/**********************************************************/
|
||
+#define DmaStoreAndForward 0x00200000 /* Store and forward RW 0 */
|
||
+#define DmaTxThreshCtl256 0x0000c000 /* Non-SF threshold is 256 words */
|
||
+#define DmaTxThreshCtl128 0x00008000 /* Non-SF threshold is 128 words */
|
||
+#define DmaTxThreshCtl064 0x00004000 /* Non-SF threshold is 64 words */
|
||
+#define DmaTxThreshCtl032 0x00000000 /* Non-SF threshold is 32 words */
|
||
+#define DmaTxStart 0x00002000 /* Start/Stop transmission RW 0 */
|
||
+#define DmaTxSecondFrame 0x00000004 /* Operate on second frame RW 0 */
|
||
+#define DmaRxStart 0x00000002 /* Start/Stop reception RW 0 */
|
||
+
|
||
+/**********************************************************/
|
||
+/* DMA interrupt enable register layout */
|
||
+/**********************************************************/
|
||
+#define DmaIeNormal DmaIntNormal /* Normal interrupt enable RW 0 */
|
||
+#define DmaIeAbnormal DmaIntAbnormal /* Abnormal interrupt enable RW 0 */
|
||
+#define DmaIeEarlyRx DmaIntEarlyRx /* Early receive interrupt enable RW 0 */
|
||
+#define DmaIeBusError DmaIntBusError /* Fatal bus error enable RW 0 */
|
||
+#define DmaIeEarlyTx DmaIntEarlyTx /* Early transmit interrupt enable RW 0 */
|
||
+#define DmaIeRxStopped DmaIntRxStopped /* Receive process stopped enable RW 0 */
|
||
+#define DmaIeRxNoBuffer DmaIntRxNoBuffer /* Receive buffer unavailable enable RW 0 */
|
||
+#define DmaIeRxCompleted DmaIntRxCompleted /* Completion of frame reception enable RW 0 */
|
||
+#define DmaIeTxUnderflow DmaIntTxUnderflow /* Transmit underflow enable RW 0 */
|
||
+#define DmaIeTxJabber DmaIntTxJabber /* Transmit jabber timeout RW 0 */
|
||
+#define DmaIeTxNoBuffer DmaIntTxNoBuffer /* Transmit buffer unavailable enable RW 0 */
|
||
+#define DmaIeTxStopped DmaIntTxStopped /* Transmit process stopped enable RW 0 */
|
||
+#define DmaIeTxCompleted DmaIntTxCompleted /* Transmit completed enable RW 0 */
|
||
+
|
||
+/****************************************************************/
|
||
+/* DMA Missed Frame and Buffer Overflow Counter register layout */
|
||
+/****************************************************************/
|
||
+#define DmaRxBufferMissedFrame 0xffff0000 /* cleared on read */
|
||
+#define DmaMissedFrameShift 16
|
||
+#define DmaRxBufferOverflowCnt 0x0000ffff /* cleared on read */
|
||
+#define DmaMissedFrameCountMask 0x0000ffff
|
||
+
|
||
+/**********************************************************/
|
||
+/* DMA Engine descriptor layout */
|
||
+/**********************************************************/
|
||
+/* status word of DMA descriptor */
|
||
+#define DescOwnByDma 0x80000000 /* Descriptor is owned by DMA engine */
|
||
+#define DescFrameLengthMask 0x3FFF0000 /* Receive descriptor frame length */
|
||
+#define DescFrameLengthShift 16
|
||
+#define DescError 0x00008000 /* Error summary bit OR of following bits */
|
||
+#define DescRxTruncated 0x00004000 /* Rx - no more descs for receive frame */
|
||
+#define DescRxLengthError 0x00001000 /* Rx - frame size not matching with length field */
|
||
+#define DescRxRunt 0x00000800 /* Rx - runt frame, damaged by a
|
||
+ collision or term before 64 bytes */
|
||
+#define DescRxMulticast 0x00000400 /* Rx - received frame is multicast */
|
||
+#define DescRxFirst 0x00000200 /* Rx - first descriptor of the frame */
|
||
+#define DescRxLast 0x00000100 /* Rx - last descriptor of the frame */
|
||
+#define DescRxLongFrame 0x00000080 /* Rx - frame is longer than 1518 bytes */
|
||
+#define DescRxLateColl 0x00000040 /* Rx - frame was damaged by a late collision */
|
||
+#define DescRxFrameEther 0x00000020 /* Rx - Frame type Ethernet 802.3*/
|
||
+#define DescRxMiiError 0x00000008 /* Rx - error reported by MII interface */
|
||
+#define DescRxDribbling 0x00000004 /* Rx - frame contains noninteger multiple of 8 bits */
|
||
+#define DescRxCrc 0x00000002 /* Rx - CRC error */
|
||
+#define DescTxTimeout 0x00004000 /* Tx - Transmit jabber timeout */
|
||
+#define DescTxLostCarrier 0x00000800 /* Tx - carrier lost during tramsmission */
|
||
+#define DescTxNoCarrier 0x00000400 /* Tx - no carrier signal from tranceiver */
|
||
+#define DescTxLateCollision 0x00000200 /* Tx - transmission aborted due to collision */
|
||
+#define DescTxExcCollisions 0x00000100 /* Tx - transmission aborted after 16 collisions */
|
||
+#define DescTxHeartbeatFail 0x00000080 /* Tx - heartbeat collision check failure */
|
||
+#define DescTxCollMask 0x00000078 /* Tx - Collision count */
|
||
+#define DescTxCollShift 3
|
||
+#define DescTxExcDeferral 0x00000004 /* Tx - excessive deferral */
|
||
+#define DescTxUnderflow 0x00000002 /* Tx - late data arrival from memory */
|
||
+#define DescTxDeferred 0x00000001 /* Tx - frame transmision deferred */
|
||
+
|
||
+/* length word of DMA descriptor */
|
||
+#define DescTxIntEnable 0x80000000 /* Tx - interrupt on completion */
|
||
+#define DescTxLast 0x40000000 /* Tx - Last segment of the frame */
|
||
+#define DescTxFirst 0x20000000 /* Tx - First segment of the frame */
|
||
+#define DescTxDisableCrc 0x04000000 /* Tx - Add CRC disabled (first segment only) */
|
||
+#define DescEndOfRing 0x02000000 /* End of descriptors ring */
|
||
+#define DescChain 0x01000000 /* Second buffer address is chain address */
|
||
+#define DescTxDisablePadd 0x00800000 /* disable padding */
|
||
+#define DescSize2Mask 0x003FF800 /* Buffer 2 size */
|
||
+#define DescSize2Shift 11
|
||
+#define DescSize1Mask 0x000007FF /* Buffer 1 size */
|
||
+#define DescSize1Shift 0
|
||
+
|
||
+/**********************************************************/
|
||
+/* Initial register values */
|
||
+/**********************************************************/
|
||
+/* Full-duplex mode with perfect filter on */
|
||
+#define MacControlInitFdx \
|
||
+ ( MacFilterOn \
|
||
+ | MacLittleEndian \
|
||
+ | MacHeartBeatOn \
|
||
+ | MacSelectMii \
|
||
+ | MacEnableRxOwn \
|
||
+ | MacLoopbackOff \
|
||
+ | MacFullDuplex \
|
||
+ | MacMulticastFilterOn \
|
||
+ | MacPromiscuousModeOff \
|
||
+ | MacFilterNormal \
|
||
+ | MacBadFramesDisable \
|
||
+ | MacPerfectFilterOn \
|
||
+ | MacHashFilterOff \
|
||
+ | MacLateCollisionOff \
|
||
+ | MacBroadcastEnable \
|
||
+ | MacRetryEnable \
|
||
+ | MacPadStripDisable \
|
||
+ | MacDeferralCheckDisable \
|
||
+ | MacTxEnable \
|
||
+ | MacRxEnable)
|
||
+
|
||
+/* Full-duplex mode */
|
||
+#define MacFlowControlInitFdx \
|
||
+ ( MacControlFrameDisable \
|
||
+ | MacFlowControlEnable)
|
||
+
|
||
+/* Half-duplex mode with perfect filter on */
|
||
+#define MacControlInitHdx \
|
||
+ ( MacFilterOn \
|
||
+ | MacLittleEndian \
|
||
+ | MacHeartBeatOn \
|
||
+ | MacSelectMii \
|
||
+ | MacDisableRxOwn \
|
||
+ | MacLoopbackOff \
|
||
+ | MacHalfDuplex \
|
||
+ | MacMulticastFilterOn \
|
||
+ | MacPromiscuousModeOff \
|
||
+ | MacFilterNormal \
|
||
+ | MacBadFramesDisable \
|
||
+ | MacPerfectFilterOn \
|
||
+ | MacHashFilterOff \
|
||
+ | MacLateCollisionOff \
|
||
+ | MacBroadcastEnable \
|
||
+ | MacRetryEnable \
|
||
+ | MacPadStripDisable \
|
||
+ | MacDeferralCheckDisable \
|
||
+ | MacTxEnable \
|
||
+ | MacRxEnable)
|
||
+
|
||
+/* Half-duplex mode */
|
||
+#define MacFlowControlInitHdx \
|
||
+ ( MacControlFrameDisable \
|
||
+ | MacFlowControlDisable)
|
||
+
|
||
+/* Bus Mode Rx odd half word align */
|
||
+#define DmaBusModeInit \
|
||
+ ( DmaLittleEndianDesc \
|
||
+ | DmaRxAlign16 \
|
||
+ | DmaBurstLength4 \
|
||
+ | DmaBigEndianData \
|
||
+ | DmaDescriptorSkip1 \
|
||
+ | DmaReceivePriorityOn \
|
||
+ | DmaResetOff)
|
||
+
|
||
+#define DmaControlInit (DmaStoreAndForward)
|
||
+
|
||
+/* Interrupt groups */
|
||
+#define DmaIntEnable \
|
||
+ ( DmaIeNormal \
|
||
+ | DmaIeAbnormal \
|
||
+ | DmaIntBusError \
|
||
+ | DmaIntRxStopped \
|
||
+ | DmaIntTxUnderflow \
|
||
+ | DmaIntTxStopped)
|
||
+
|
||
+#define DmaIntDisable 0
|
||
+
|
||
+#define DmaAllIntCauseMask \
|
||
+ ( DmaIeNormal \
|
||
+ | DmaIeAbnormal \
|
||
+ | DmaIntEarlyRx \
|
||
+ | DmaIntBusError \
|
||
+ | DmaIntEarlyTx \
|
||
+ | DmaIntRxStopped \
|
||
+ | DmaIntRxNoBuffer \
|
||
+ | DmaIntRxCompleted \
|
||
+ | DmaIntTxUnderflow \
|
||
+ | DmaIntTxJabber \
|
||
+ | DmaIntTxNoBuffer \
|
||
+ | DmaIntTxStopped \
|
||
+ | DmaIntTxCompleted)
|
||
+
|
||
+#define UnhandledIntrMask \
|
||
+ (DmaAllIntCauseMask \
|
||
+ & ~(DmaIntRxNoBuffer \
|
||
+ | DmaIntTxStopped \
|
||
+ | DmaIntTxJabber \
|
||
+ | DmaIntTxUnderflow \
|
||
+ | DmaIntBusError \
|
||
+ | DmaIntRxCompleted ))
|
||
+
|
||
+#define DescRxErrors \
|
||
+ (DescRxTruncated \
|
||
+ | DescRxRunt \
|
||
+ | DescRxLateColl \
|
||
+ | DescRxMiiError \
|
||
+ | DescRxCrc)
|
||
+
|
||
+#define DescTxErrors \
|
||
+ ( DescTxTimeout \
|
||
+ | DescTxLateCollision \
|
||
+ | DescTxExcCollisions \
|
||
+ | DescTxExcDeferral \
|
||
+ | DescTxUnderflow)
|
||
+
|
||
+/**********************************************************/
|
||
+/* Descriptor Layout */
|
||
+/**********************************************************/
|
||
+#define AE531X_DESC_STATUS 0x00 /* Status offset */
|
||
+#define AE531X_DESC_CTRLEN 0x04 /* Control and Length offset */
|
||
+#define AE531X_DESC_BUFPTR 0x08 /* Buffer pointer offset */
|
||
+#define AE531X_DESC_LNKBUF 0x0c /* Link field offset, or ptr to 2nd buf */
|
||
+#define AE531X_DESC_SWPTR 0x10 /* OS-Dependent software pointer */
|
||
+
|
||
+#define AE531X_DESC_SIZE 0x10 /* 4 words, 16 bytes */
|
||
+#define AE531X_QUEUE_ELE_SIZE 0x14 /* with software pointer extension */
|
||
+
|
||
+/* Accessors to the dma descriptor fields */
|
||
+#define AE531X_DESC_STATUS_GET(ptr) \
|
||
+ *(volatile UINT32 *)((UINT32)(ptr) + AE531X_DESC_STATUS)
|
||
+
|
||
+#define AE531X_DESC_STATUS_SET(ptr, val) \
|
||
+ AE531X_DESC_STATUS_GET(ptr) = (val)
|
||
+
|
||
+#define AE531X_DESC_CTRLEN_GET(ptr) \
|
||
+ *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_CTRLEN)
|
||
+
|
||
+#define AE531X_DESC_CTRLEN_SET(ptr, val) \
|
||
+ AE531X_DESC_CTRLEN_GET(ptr) = (val)
|
||
+
|
||
+#define AE531X_DESC_BUFPTR_GET(ptr) \
|
||
+ *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_BUFPTR)
|
||
+
|
||
+#define AE531X_DESC_BUFPTR_SET(ptr,val) \
|
||
+ AE531X_DESC_BUFPTR_GET(ptr) = (UINT32)(val)
|
||
+
|
||
+#define AE531X_DESC_LNKBUF_GET(ptr) \
|
||
+ *(volatile UINT32 *)((UINT32)ptr + AE531X_DESC_LNKBUF)
|
||
+
|
||
+#define AE531X_DESC_LNKBUF_SET(ptr, val) \
|
||
+ AE531X_DESC_LNKBUF_GET(ptr) = (val)
|
||
+
|
||
+#define AE531X_DESC_SWPTR_GET(ptr) \
|
||
+ (void *)(*(volatile UINT32 *) ((UINT32)ptr + AE531X_DESC_SWPTR))
|
||
+
|
||
+#define AE531X_DESC_SWPTR_SET(ptr,val) \
|
||
+ AE531X_DESC_SWPTR_GET(ptr) = (void *)(val)
|
||
+
|
||
+/* Get size of Rx data from desc, in bytes */
|
||
+#define AE531X_DESC_STATUS_RX_SIZE(x) \
|
||
+ (((x) & DescFrameLengthMask) >> DescFrameLengthShift)
|
||
+
|
||
+#endif /* _AE531XREG_H_ */
|
||
diff -urN linux-2.4.32.new/arch/mips/ar531x/Makefile linux-2.4.32.new-eth/arch/mips/ar531x/Makefile
|
||
--- linux-2.4.32.new/arch/mips/ar531x/Makefile 2005-12-24 20:29:42.010325312 +0000
|
||
+++ linux-2.4.32.new-eth/arch/mips/ar531x/Makefile 2005-12-25 12:03:16.213872024 +0000
|
||
@@ -28,6 +28,13 @@
|
||
ar531xirq.o \
|
||
ar531xintr.o \
|
||
ar531xgpio.o \
|
||
- ar531xksyms.o
|
||
+ ar531xksyms.o \
|
||
+ ae531xlnx.o \
|
||
+ ae531xmac.o
|
||
|
||
include $(TOPDIR)/Rules.make
|
||
+obj-$(CONFIG_MARVELL_ENET_PHY) += mvPhy.o
|
||
+obj-$(CONFIG_KENDIN_ENET_PHY)) += rtPhy.o
|
||
+obj-$(CONFIG_REALTEK_ENET_PHY) += rtPhy.o
|
||
+
|
||
+
|
||
diff -urN linux-2.4.32.new/arch/mips/ar531x/mvPhy.c linux-2.4.32.new-eth/arch/mips/ar531x/mvPhy.c
|
||
--- linux-2.4.32.new/arch/mips/ar531x/mvPhy.c 1970-01-01 01:00:00.000000000 +0100
|
||
+++ linux-2.4.32.new-eth/arch/mips/ar531x/mvPhy.c 2005-12-25 11:54:39.730389448 +0000
|
||
@@ -0,0 +1,1237 @@
|
||
+/*
|
||
+ * This file is subject to the terms and conditions of the GNU General Public
|
||
+ * License. See the file "COPYING" in the main directory of this archive
|
||
+ * for more details.
|
||
+ *
|
||
+ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
|
||
+ */
|
||
+
|
||
+/*
|
||
+* Manage the ethernet PHY switch, Marvell 88E6060.
|
||
+*
|
||
+* This module is intended to be largely OS and platform-independent.
|
||
+*/
|
||
+
|
||
+#if defined(linux)
|
||
+#include <linux/config.h>
|
||
+#include <linux/types.h>
|
||
+#include <linux/netdevice.h>
|
||
+#include <linux/etherdevice.h>
|
||
+#include <linux/delay.h>
|
||
+
|
||
+#include "ar531xlnx.h"
|
||
+#endif
|
||
+
|
||
+#if defined(__ECOS)
|
||
+#include "ae531xecos.h"
|
||
+#endif
|
||
+
|
||
+
|
||
+#include "ae531xmac.h"
|
||
+#include "ae531xreg.h"
|
||
+#include "mvPhy.h"
|
||
+
|
||
+#if /* DEBUG */ 1
|
||
+#define MV_DEBUG_ERROR 0x00000001
|
||
+#define MV_DEBUG_PHYSETUP 0x00000002
|
||
+#define MV_DEBUG_PHYCHANGE 0x00000004
|
||
+
|
||
+int mvPhyDebug = MV_DEBUG_ERROR;
|
||
+
|
||
+#define MV_PRINT(FLG, X) \
|
||
+{ \
|
||
+ if (mvPhyDebug & (FLG)) { \
|
||
+ DEBUG_PRINTF X; \
|
||
+ } \
|
||
+}
|
||
+#else
|
||
+#define MV_PRINT(FLG, X)
|
||
+#endif
|
||
+
|
||
+#ifdef CONFIG_VENETDEV
|
||
+/*
|
||
+ * On AR5312 with CONFIG_VENETDEV==1,
|
||
+ * ports 0..3 are LAN ports (accessed through ae0)
|
||
+ * port 4 is the WAN port. (accessed through ae1)
|
||
+ *
|
||
+ * The phy switch settings in the mvPhyInfo table are set accordingly.
|
||
+ */
|
||
+#define MV_WAN_PORT 4
|
||
+#define MV_IS_LAN_PORT(port) ((port) < MV_WAN_PORT)
|
||
+#define MV_IS_WAN_PORT(port) ((port) == MV_WAN_PORT)
|
||
+#endif
|
||
+
|
||
+/*
|
||
+ * Track per-PHY port information.
|
||
+ */
|
||
+typedef struct {
|
||
+ BOOL isEnetPort; /* normal enet port */
|
||
+ BOOL isPhyAlive; /* last known state of link */
|
||
+ int ethUnit; /* MAC associated with this phy port */
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr; /* PHY registers associated with this phy port */
|
||
+ UINT32 switchPortAddr; /* switch port regs assoc'ed with this phy port */
|
||
+ UINT32 VLANTableSetting; /* Value to be written to VLAN table */
|
||
+} mvPhyInfo_t;
|
||
+
|
||
+/******************************************************************************
|
||
+ * Per-PHY information, indexed by PHY unit number.
|
||
+ *
|
||
+ * This table is board-dependent. It includes information
|
||
+ * about which enet MAC controls which PHY port.
|
||
+ */
|
||
+mvPhyInfo_t mvPhyInfo[] = {
|
||
+ /*
|
||
+ * On AP30/AR5312, all PHYs are associated with MAC0.
|
||
+ * AP30/AR5312's MAC1 isn't used for anything.
|
||
+ * CONFIG_VENETDEV==1 (router) configuration:
|
||
+ * Ports 0,1,2, and 3 are "LAN ports"
|
||
+ * Port 4 is a WAN port
|
||
+ * Port 5 connects to MAC0 in the AR5312
|
||
+ * CONFIG_VENETDEV==0 (bridge) configuration:
|
||
+ * Ports 0,1,2,3,4 are "LAN ports"
|
||
+ * Port 5 connects to the MAC0 in the AR5312
|
||
+ */
|
||
+ {isEnetPort: TRUE, /* phy port 0 -- LAN port 0 */
|
||
+ isPhyAlive: FALSE,
|
||
+ ethUnit: 0,
|
||
+ phyBase: 0,
|
||
+ phyAddr: 0x10,
|
||
+ switchPortAddr: 0x18,
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ VLANTableSetting: 0x2e
|
||
+#else
|
||
+ VLANTableSetting: 0x3e
|
||
+#endif
|
||
+ },
|
||
+
|
||
+ {isEnetPort: TRUE, /* phy port 1 -- LAN port 1 */
|
||
+ isPhyAlive: FALSE,
|
||
+ ethUnit: 0,
|
||
+ phyBase: 0,
|
||
+ phyAddr: 0x11,
|
||
+ switchPortAddr: 0x19,
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ VLANTableSetting: 0x2d
|
||
+#else
|
||
+ VLANTableSetting: 0x3d
|
||
+#endif
|
||
+ },
|
||
+
|
||
+ {isEnetPort: TRUE, /* phy port 2 -- LAN port 2 */
|
||
+ isPhyAlive: FALSE,
|
||
+ ethUnit: 0,
|
||
+ phyBase: 0,
|
||
+ phyAddr: 0x12,
|
||
+ switchPortAddr: 0x1a,
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ VLANTableSetting: 0x2b
|
||
+#else
|
||
+ VLANTableSetting: 0x3b
|
||
+#endif
|
||
+ },
|
||
+
|
||
+ {isEnetPort: TRUE, /* phy port 3 -- LAN port 3 */
|
||
+ isPhyAlive: FALSE,
|
||
+ ethUnit: 0,
|
||
+ phyBase: 0,
|
||
+ phyAddr: 0x13,
|
||
+ switchPortAddr: 0x1b,
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ VLANTableSetting: 0x27
|
||
+#else
|
||
+ VLANTableSetting: 0x37
|
||
+#endif
|
||
+ },
|
||
+
|
||
+ {isEnetPort: TRUE, /* phy port 4 -- WAN port or LAN port 4 */
|
||
+ isPhyAlive: FALSE,
|
||
+ ethUnit: 0,
|
||
+ phyBase: 0,
|
||
+ phyAddr: 0x14,
|
||
+ switchPortAddr: 0x1c,
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ VLANTableSetting: 0x1020 /* WAN port */
|
||
+#else
|
||
+ VLANTableSetting: 0x2f /* LAN port 4 */
|
||
+#endif
|
||
+ },
|
||
+
|
||
+ {isEnetPort: FALSE, /* phy port 5 -- CPU port (no RJ45 connector) */
|
||
+ isPhyAlive: TRUE,
|
||
+ ethUnit: 0,
|
||
+ phyBase: 0,
|
||
+ phyAddr: 0x15,
|
||
+ switchPortAddr: 0x1d,
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ VLANTableSetting: 0x0f /* Send only to LAN ports */
|
||
+#else
|
||
+ VLANTableSetting: 0x1f /* Send to all ports */
|
||
+#endif
|
||
+ },
|
||
+};
|
||
+
|
||
+#define MV_PHY_MAX (sizeof(mvPhyInfo) / sizeof(mvPhyInfo[0]))
|
||
+
|
||
+/* Range of valid PHY IDs is [MIN..MAX] */
|
||
+#define MV_ID_MIN 0
|
||
+#define MV_ID_MAX (MV_PHY_MAX-1)
|
||
+
|
||
+/* Convenience macros to access myPhyInfo */
|
||
+#define MV_IS_ENET_PORT(phyUnit) (mvPhyInfo[phyUnit].isEnetPort)
|
||
+#define MV_IS_PHY_ALIVE(phyUnit) (mvPhyInfo[phyUnit].isPhyAlive)
|
||
+#define MV_ETHUNIT(phyUnit) (mvPhyInfo[phyUnit].ethUnit)
|
||
+#define MV_PHYBASE(phyUnit) (mvPhyInfo[phyUnit].phyBase)
|
||
+#define MV_PHYADDR(phyUnit) (mvPhyInfo[phyUnit].phyAddr)
|
||
+#define MV_SWITCH_PORT_ADDR(phyUnit) (mvPhyInfo[phyUnit].switchPortAddr)
|
||
+#define MV_VLAN_TABLE_SETTING(phyUnit) (mvPhyInfo[phyUnit].VLANTableSetting)
|
||
+
|
||
+#define MV_IS_ETHUNIT(phyUnit, ethUnit) \
|
||
+ (MV_IS_ENET_PORT(phyUnit) && \
|
||
+ MV_ETHUNIT(phyUnit) == (ethUnit))
|
||
+
|
||
+
|
||
+/* Forward references */
|
||
+BOOL mv_phyIsLinkAlive(int phyUnit);
|
||
+LOCAL void mv_VLANInit(int ethUnit);
|
||
+LOCAL void mv_enableConfiguredPorts(int ethUnit);
|
||
+LOCAL void mv_verifyReady(int ethUnit);
|
||
+BOOL mv_phySetup(int ethUnit, UINT32 phyBase);
|
||
+BOOL mv_phyIsFullDuplex(int ethUnit);
|
||
+BOOL mv_phyIsSpeed100(int phyUnit);
|
||
+LOCAL BOOL mv_validPhyId(int phyUnit);
|
||
+void mv_flushATUDB(int phyUnit);
|
||
+void mv_phyCheckStatusChange(int ethUnit);
|
||
+#if DEBUG
|
||
+void mv_phyShow(int phyUnit);
|
||
+void mv_phySet(int phyUnit, UINT32 regnum, UINT32 value);
|
||
+void mv_switchPortSet(int phyUnit, UINT32 regnum, UINT32 value);
|
||
+void mv_switchGlobalSet(int phyUnit, UINT32 regnum, UINT32 value);
|
||
+void mv_showATUDB(int phyUnit);
|
||
+void mv_countGoodFrames(int phyUnit);
|
||
+void mv_countBadFrames(int phyUnit);
|
||
+void mv_showFrameCounts(int phyUnit);
|
||
+#endif
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* mv_phyIsLinkAlive - test to see if the specified link is alive
|
||
+*
|
||
+* RETURNS:
|
||
+* TRUE --> link is alive
|
||
+* FALSE --> link is down
|
||
+*/
|
||
+BOOL
|
||
+mv_phyIsLinkAlive(int phyUnit)
|
||
+{
|
||
+ UINT16 phyHwStatus;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+
|
||
+ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
|
||
+
|
||
+ if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) {
|
||
+ return TRUE;
|
||
+ } else {
|
||
+ return FALSE;
|
||
+ }
|
||
+}
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* mv_VLANInit - initialize "port-based VLANs" for the specified enet unit.
|
||
+*/
|
||
+LOCAL void
|
||
+mv_VLANInit(int ethUnit)
|
||
+{
|
||
+ int phyUnit;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 switchPortAddr;
|
||
+
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+ if (MV_ETHUNIT(phyUnit) != ethUnit) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
|
||
+
|
||
+ phyRegWrite(phyBase, switchPortAddr, MV_PORT_BASED_VLAN_MAP,
|
||
+ MV_VLAN_TABLE_SETTING(phyUnit));
|
||
+ }
|
||
+}
|
||
+
|
||
+#define phyPortConfigured(phyUnit) TRUE /* TBDFREEDOM2 */
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* mv_enableConfiguredPorts - enable whichever PHY ports are supposed
|
||
+* to be enabled according to administrative configuration.
|
||
+*/
|
||
+LOCAL void
|
||
+mv_enableConfiguredPorts(int ethUnit)
|
||
+{
|
||
+ int phyUnit;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 switchPortAddr;
|
||
+ UINT16 portControl;
|
||
+ UINT16 portAssociationVector;
|
||
+
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+ if (MV_ETHUNIT(phyUnit) != ethUnit) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
|
||
+
|
||
+ if (phyPortConfigured(phyUnit)) {
|
||
+
|
||
+ portControl = MV_PORT_CONTROL_PORT_STATE_FORWARDING;
|
||
+#ifdef CONFIG_VENETDEV
|
||
+ if (!MV_IS_ENET_PORT(phyUnit)) { /* CPU port */
|
||
+ portControl |= MV_PORT_CONTROL_INGRESS_TRAILER
|
||
+ | MV_PORT_CONTROL_EGRESS_MODE;
|
||
+ }
|
||
+#endif
|
||
+ phyRegWrite(phyBase, switchPortAddr, MV_PORT_CONTROL, portControl);
|
||
+
|
||
+ if (MV_IS_ENET_PORT(phyUnit)) {
|
||
+ portAssociationVector = 1 << phyUnit;
|
||
+ } else {
|
||
+ /* Disable learning on the CPU port */
|
||
+ portAssociationVector = 0;
|
||
+ }
|
||
+ phyRegWrite(phyBase, switchPortAddr,
|
||
+ MV_PORT_ASSOCIATION_VECTOR, portAssociationVector);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* mv_verifyReady - validates that we're dealing with the device
|
||
+* we think we're dealing with, and that it's ready.
|
||
+*/
|
||
+LOCAL void
|
||
+mv_verifyReady(int ethUnit)
|
||
+{
|
||
+ int phyUnit;
|
||
+ UINT16 globalStatus;
|
||
+ UINT32 phyBase = 0;
|
||
+ UINT32 phyAddr;
|
||
+ UINT32 switchPortAddr;
|
||
+ UINT16 phyID1;
|
||
+ UINT16 phyID2;
|
||
+ UINT16 switchID;
|
||
+
|
||
+ /*
|
||
+ * The first read to the Phy port registers always fails and
|
||
+ * returns 0. So get things started with a bogus read.
|
||
+ */
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
|
||
+ continue;
|
||
+ }
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+
|
||
+ (void)phyRegRead(phyBase, phyAddr, MV_PHY_ID1); /* returns 0 */
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ /*******************/
|
||
+ /* Verify phy port */
|
||
+ /*******************/
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+
|
||
+ phyID1 = phyRegRead(phyBase, phyAddr, MV_PHY_ID1);
|
||
+ if (phyID1 != MV_PHY_ID1_EXPECTATION) {
|
||
+ MV_PRINT(MV_DEBUG_PHYSETUP,
|
||
+ ("Invalid PHY ID1 for ethmac%d port%d. Expected 0x%04x, read 0x%04x\n",
|
||
+ ethUnit,
|
||
+ phyUnit,
|
||
+ MV_PHY_ID1_EXPECTATION,
|
||
+ phyID1));
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ phyID2 = phyRegRead(phyBase, phyAddr, MV_PHY_ID2);
|
||
+ if ((phyID2 & MV_OUI_LSB_MASK) != MV_OUI_LSB_EXPECTATION) {
|
||
+ MV_PRINT(MV_DEBUG_PHYSETUP,
|
||
+ ("Invalid PHY ID2 for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n",
|
||
+ ethUnit,
|
||
+ phyUnit,
|
||
+ MV_OUI_LSB_EXPECTATION,
|
||
+ phyID2));
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ MV_PRINT(MV_DEBUG_PHYSETUP,
|
||
+ ("Found PHY ethmac%d port%d: model 0x%x revision 0x%x\n",
|
||
+ ethUnit,
|
||
+ phyUnit,
|
||
+ (phyID2 & MV_MODEL_NUM_MASK) >> MV_MODEL_NUM_SHIFT,
|
||
+ (phyID2 & MV_REV_NUM_MASK) >> MV_REV_NUM_SHIFT));
|
||
+
|
||
+
|
||
+ /**********************/
|
||
+ /* Verify switch port */
|
||
+ /**********************/
|
||
+ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
|
||
+
|
||
+ switchID = phyRegRead(phyBase, switchPortAddr, MV_SWITCH_ID);
|
||
+ if ((switchID & MV_SWITCH_ID_DEV_MASK) !=
|
||
+ MV_SWITCH_ID_DEV_EXPECTATION) {
|
||
+
|
||
+ MV_PRINT(MV_DEBUG_PHYSETUP,
|
||
+ ("Invalid switch ID for ethmac%d port %d. Expected 0x%04x, read 0x%04x\n",
|
||
+ ethUnit,
|
||
+ phyUnit,
|
||
+ MV_SWITCH_ID_DEV_EXPECTATION,
|
||
+ switchID));
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ MV_PRINT(MV_DEBUG_PHYSETUP,
|
||
+ ("Found PHY switch for enet %d port %d deviceID 0x%x revision 0x%x\n",
|
||
+ ethUnit,
|
||
+ phyUnit,
|
||
+ (switchID & MV_SWITCH_ID_DEV_MASK) >> MV_SWITCH_ID_DEV_SHIFT,
|
||
+ (switchID & MV_SWITCH_ID_REV_MASK) >> MV_SWITCH_ID_REV_SHIFT))
|
||
+ }
|
||
+
|
||
+ /*******************************/
|
||
+ /* Verify that switch is ready */
|
||
+ /*******************************/
|
||
+ if (phyBase) {
|
||
+ globalStatus = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
|
||
+ MV_SWITCH_GLOBAL_STATUS);
|
||
+
|
||
+ if (!(globalStatus & MV_SWITCH_STATUS_READY_MASK)) {
|
||
+ MV_PRINT(MV_DEBUG_PHYSETUP,
|
||
+ ("PHY switch for ethmac%d NOT ready!\n",
|
||
+ ethUnit));
|
||
+ }
|
||
+ } else {
|
||
+ MV_PRINT(MV_DEBUG_PHYSETUP,
|
||
+ ("No ports configured for ethmac%d\n", ethUnit));
|
||
+ }
|
||
+}
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* mv_phySetup - reset and setup the PHY switch.
|
||
+*
|
||
+* Resets each PHY port.
|
||
+*
|
||
+* RETURNS:
|
||
+* TRUE --> at least 1 PHY with LINK
|
||
+* FALSE --> no LINKs on this ethernet unit
|
||
+*/
|
||
+BOOL
|
||
+mv_phySetup(int ethUnit, UINT32 phyBase)
|
||
+{
|
||
+ int phyUnit;
|
||
+ int liveLinks = 0;
|
||
+ BOOL foundPhy = FALSE;
|
||
+ UINT32 phyAddr;
|
||
+ UINT16 atuControl;
|
||
+
|
||
+ /*
|
||
+ * Allow platform-specific code to determine the default Ethernet MAC
|
||
+ * at run-time. If phyEthMacDefault returns a negative value, use the
|
||
+ * static mvPhyInfo table "as is". But if phyEthMacDefault returns a
|
||
+ * non-negative value, use it as the default ethernet unit.
|
||
+ */
|
||
+ {
|
||
+ int ethMacDefault = phyEthMacDefault();
|
||
+
|
||
+ if (ethMacDefault >= 0) {
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+ MV_ETHUNIT(phyUnit)=ethMacDefault;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * See if there's any configuration data for this enet,
|
||
+ * and set up phyBase in table.
|
||
+ */
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+ if (MV_ETHUNIT(phyUnit) != ethUnit) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ MV_PHYBASE(phyUnit) = phyBase;
|
||
+ foundPhy = TRUE;
|
||
+ }
|
||
+
|
||
+ if (!foundPhy) {
|
||
+ return FALSE; /* No PHY's configured for this ethUnit */
|
||
+ }
|
||
+
|
||
+ /* Verify that the switch is what we think it is, and that it's ready */
|
||
+ mv_verifyReady(ethUnit);
|
||
+
|
||
+ /* Initialize global switch settings */
|
||
+ atuControl = MV_ATUCTRL_AGE_TIME_DEFAULT << MV_ATUCTRL_AGE_TIME_SHIFT;
|
||
+ atuControl |= MV_ATUCTRL_ATU_SIZE_DEFAULT << MV_ATUCTRL_ATU_SIZE_SHIFT;
|
||
+ // atuControl |= MV_ATUCTRL_ATU_LEARNDIS;
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_CONTROL, atuControl);
|
||
+
|
||
+ /* Reset PHYs and start autonegoation on each. */
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+ if (MV_ETHUNIT(phyUnit) != ethUnit) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+
|
||
+ phyRegWrite(phyBase, phyAddr, MV_PHY_CONTROL,
|
||
+ MV_CTRL_SOFTWARE_RESET | MV_CTRL_AUTONEGOTIATION_ENABLE);
|
||
+ }
|
||
+
|
||
+ {
|
||
+ int timeout;
|
||
+ UINT16 phyHwStatus;
|
||
+
|
||
+ /*
|
||
+ * Wait 5 seconds for ALL associated PHYs to finish autonegotiation.
|
||
+ */
|
||
+ timeout=50;
|
||
+ for (phyUnit=0; (phyUnit < MV_PHY_MAX) && (timeout > 0); phyUnit++) {
|
||
+ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
|
||
+ continue;
|
||
+ }
|
||
+ for (;;) {
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+
|
||
+ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
|
||
+
|
||
+ if (MV_AUTONEG_DONE(phyHwStatus)) {
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (--timeout == 0) {
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ sysMsDelay(100);
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /*
|
||
+ * All PHYs have had adequate time to autonegotiate.
|
||
+ * Now initialize software status.
|
||
+ *
|
||
+ * It's possible that some ports may take a bit longer
|
||
+ * to autonegotiate; but we can't wait forever. They'll
|
||
+ * get noticed by mv_phyCheckStatusChange during regular
|
||
+ * polling activities.
|
||
+ */
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ if (mv_phyIsLinkAlive(phyUnit)) {
|
||
+ liveLinks++;
|
||
+ MV_IS_PHY_ALIVE(phyUnit) = TRUE;
|
||
+#ifdef DEBUG
|
||
+ mv_phyShow(phyUnit);
|
||
+#endif
|
||
+ } else {
|
||
+ MV_IS_PHY_ALIVE(phyUnit) = FALSE;
|
||
+ }
|
||
+
|
||
+ MV_PRINT(MV_DEBUG_PHYSETUP,
|
||
+ ("ethmac%d: Phy Status=%4.4x\n",
|
||
+ ethUnit,
|
||
+ phyRegRead(MV_PHYBASE(phyUnit),
|
||
+ MV_PHYADDR(phyUnit),
|
||
+ MV_PHY_SPECIFIC_STATUS)));
|
||
+
|
||
+ }
|
||
+
|
||
+#ifdef DEBUG
|
||
+ /* PHY 5 is the connection to the CPU */
|
||
+ mv_phyShow(5);
|
||
+#endif
|
||
+
|
||
+ mv_VLANInit(ethUnit);
|
||
+
|
||
+ mv_enableConfiguredPorts(ethUnit);
|
||
+
|
||
+ return (liveLinks > 0);
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* mv_phyIsDuplexFull - Determines whether the phy ports associated with the
|
||
+* specified device are FULL or HALF duplex.
|
||
+*
|
||
+* RETURNS:
|
||
+* TRUE --> at least one associated PHY in FULL DUPLEX
|
||
+* FALSE --> all half duplex, or no links
|
||
+*/
|
||
+BOOL
|
||
+mv_phyIsFullDuplex(int ethUnit)
|
||
+{
|
||
+ int phyUnit;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+ UINT16 phyHwStatus;
|
||
+
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+
|
||
+ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ if (mv_phyIsLinkAlive(phyUnit)) {
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+
|
||
+ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
|
||
+
|
||
+ if (phyHwStatus & MV_STATUS_RESOLVED_DUPLEX_FULL) {
|
||
+ return TRUE;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return FALSE;
|
||
+}
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* mv_phyIsSpeed100 - Determines the speed of a phy port
|
||
+*
|
||
+* RETURNS:
|
||
+* TRUE --> PHY operating at 100 Mbit
|
||
+* FALSE --> link down, or not operating at 100 Mbit
|
||
+*/
|
||
+BOOL
|
||
+mv_phyIsSpeed100(int phyUnit)
|
||
+{
|
||
+ UINT16 phyHwStatus;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ if (MV_IS_ENET_PORT(phyUnit)) {
|
||
+ if (mv_phyIsLinkAlive(phyUnit)) {
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+
|
||
+ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
|
||
+
|
||
+ if (phyHwStatus & MV_STATUS_RESOLVED_SPEED_100) {
|
||
+ return TRUE;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return FALSE;
|
||
+}
|
||
+
|
||
+#ifdef CONFIG_VENETDEV
|
||
+/******************************************************************************
|
||
+*
|
||
+* mv_phyDetermineSource - Examine a received frame's Egress Trailer
|
||
+* to determine whether it came from a LAN or WAN port.
|
||
+*
|
||
+* RETURNS:
|
||
+* Returns 1-->LAN, 0-->WAN, -1-->ERROR
|
||
+*/
|
||
+int
|
||
+mv_phyDetermineSource(char *data, int len)
|
||
+{
|
||
+ unsigned char *phyTrailer;
|
||
+ unsigned char incomingPort;
|
||
+
|
||
+ phyTrailer = &data[len - MV_PHY_TRAILER_SIZE];
|
||
+
|
||
+ /* ASSERT(phyTrailer[0] == MV_EGRESS_TRAILER_VALID); */
|
||
+ if (phyTrailer[0] != MV_EGRESS_TRAILER_VALID) {
|
||
+ printk(KERN_ERR "PHY trailer invalid; got %#02x, expected %#02x\n",
|
||
+ phyTrailer[0], MV_EGRESS_TRAILER_VALID);
|
||
+ return -1;
|
||
+ }
|
||
+
|
||
+ incomingPort = phyTrailer[1];
|
||
+ if (MV_IS_LAN_PORT(incomingPort)) {
|
||
+ return 1;
|
||
+ } else {
|
||
+ /* ASSERT(MV_IS_WAN_PORT(incomingPort)); */
|
||
+ if (!MV_IS_WAN_PORT(incomingPort)) {
|
||
+ printk(KERN_ERR "incoming port was %d; expected 0-4\n", incomingPort);
|
||
+ return -1;
|
||
+ }
|
||
+ return 0;
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* mv_phySetDestinationPort - Set the Ingress Trailer to force the
|
||
+* frame to be sent to LAN or WAN, as specified.
|
||
+*
|
||
+*/
|
||
+void
|
||
+mv_phySetDestinationPort(char *data, int len, int fromLAN)
|
||
+{
|
||
+ char *phyTrailer;
|
||
+
|
||
+ phyTrailer = &data[len];
|
||
+ if (fromLAN) {
|
||
+ /* LAN ports: Use default settings, as per mvPhyInfo */
|
||
+ phyTrailer[0] = 0x00;
|
||
+ phyTrailer[1] = 0x00;
|
||
+ } else {
|
||
+ /* WAN port: Direct to WAN port */
|
||
+ phyTrailer[0] = MV_INGRESS_TRAILER_OVERRIDE;
|
||
+ phyTrailer[1] = 1 << MV_WAN_PORT;
|
||
+ }
|
||
+ phyTrailer[2] = 0x00;
|
||
+ phyTrailer[3] = 0x00;
|
||
+}
|
||
+#endif
|
||
+
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* Validate that the specified PHY unit number is a valid PHY ID.
|
||
+* Print a message if it is invalid.
|
||
+* RETURNS
|
||
+* TRUE --> valid
|
||
+* FALSE --> invalid
|
||
+*/
|
||
+LOCAL BOOL
|
||
+mv_validPhyId(int phyUnit)
|
||
+{
|
||
+ if ((phyUnit >= MV_ID_MIN) && (phyUnit <= MV_ID_MAX)) {
|
||
+ return TRUE;
|
||
+ } else {
|
||
+ PRINTF("PHY unit number must be in the range [%d..%d]\n",
|
||
+ MV_ID_MIN, MV_ID_MAX);
|
||
+ return FALSE;
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_waitWhileATUBusy - spins until the ATU completes
|
||
+* its previous operation.
|
||
+*/
|
||
+LOCAL void
|
||
+mv_waitWhileATUBusy(UINT32 phyBase)
|
||
+{
|
||
+ BOOL isBusy;
|
||
+ UINT16 ATUOperation;
|
||
+
|
||
+ do {
|
||
+
|
||
+ ATUOperation = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
|
||
+ MV_ATU_OPERATION);
|
||
+
|
||
+ isBusy = (ATUOperation & MV_ATU_BUSY_MASK) == MV_ATU_IS_BUSY;
|
||
+
|
||
+ } while(isBusy);
|
||
+}
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_flushATUDB - flushes ALL entries in the Address Translation Unit
|
||
+* DataBase associated with phyUnit. [Since we use a single DB for
|
||
+* all PHYs, this flushes the entire shared DataBase.]
|
||
+*
|
||
+* The current implementation flushes even more than absolutely needed --
|
||
+* it flushes all entries for all phyUnits on the same ethernet as the
|
||
+* specified phyUnit.
|
||
+*
|
||
+* It is called only when a link failure is detected on a port that was
|
||
+* previously working. In other words, when the cable is unplugged.
|
||
+*/
|
||
+void
|
||
+mv_flushATUDB(int phyUnit)
|
||
+{
|
||
+ UINT32 phyBase;
|
||
+
|
||
+ if (!mv_validPhyId(phyUnit)) {
|
||
+ PRINTF("Invalid port number: %d\n", phyUnit);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+
|
||
+ /* Wait for previous operation (if any) to complete */
|
||
+ mv_waitWhileATUBusy(phyBase);
|
||
+
|
||
+ /* Tell hardware to flush all entries */
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION,
|
||
+ MV_ATU_OP_FLUSH_ALL | MV_ATU_IS_BUSY);
|
||
+
|
||
+ mv_waitWhileATUBusy(phyBase);
|
||
+}
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_phyCheckStatusChange -- checks for significant changes in PHY state.
|
||
+*
|
||
+* A "significant change" is:
|
||
+* dropped link (e.g. ethernet cable unplugged) OR
|
||
+* autonegotiation completed + link (e.g. ethernet cable plugged in)
|
||
+*/
|
||
+void
|
||
+mv_phyCheckStatusChange(int ethUnit)
|
||
+{
|
||
+ int phyUnit;
|
||
+ UINT16 phyHwStatus;
|
||
+ mvPhyInfo_t *lastStatus;
|
||
+ int linkCount = 0;
|
||
+ int lostLinks = 0;
|
||
+ int gainedLinks = 0;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ for (phyUnit=0; phyUnit < MV_PHY_MAX; phyUnit++) {
|
||
+ if (!MV_IS_ETHUNIT(phyUnit, ethUnit)) {
|
||
+ continue;
|
||
+ }
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+
|
||
+ lastStatus = &mvPhyInfo[phyUnit];
|
||
+ phyHwStatus = phyRegRead(phyBase, phyAddr, MV_PHY_SPECIFIC_STATUS);
|
||
+
|
||
+ if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */
|
||
+ /* See if we've lost link */
|
||
+ if (phyHwStatus & MV_STATUS_REAL_TIME_LINK_UP) {
|
||
+ linkCount++;
|
||
+ } else {
|
||
+ lostLinks++;
|
||
+ mv_flushATUDB(phyUnit);
|
||
+ MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d down\n",
|
||
+ ethUnit, phyUnit));
|
||
+ lastStatus->isPhyAlive = FALSE;
|
||
+ }
|
||
+ } else { /* last known link status was DEAD */
|
||
+ /* Check for AutoNegotiation complete */
|
||
+ if (MV_AUTONEG_DONE(phyHwStatus)) {
|
||
+ gainedLinks++;
|
||
+ linkCount++;
|
||
+ MV_PRINT(MV_DEBUG_PHYCHANGE,("\nethmac%d port%d up\n",
|
||
+ ethUnit, phyUnit));
|
||
+ lastStatus->isPhyAlive = TRUE;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ if (linkCount == 0) {
|
||
+ if (lostLinks) {
|
||
+ /* We just lost the last link for this MAC */
|
||
+ phyLinkLost(ethUnit);
|
||
+ }
|
||
+ } else {
|
||
+ if (gainedLinks == linkCount) {
|
||
+ /* We just gained our first link(s) for this MAC */
|
||
+ phyLinkGained(ethUnit);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+#if DEBUG
|
||
+
|
||
+/* Define the registers of interest for a phyShow command */
|
||
+typedef struct mvRegisterTableEntry_s {
|
||
+ UINT32 regNum;
|
||
+ char *regIdString;
|
||
+} mvRegisterTableEntry_t;
|
||
+
|
||
+mvRegisterTableEntry_t mvPhyRegisterTable[] = {
|
||
+ {MV_PHY_CONTROL, "PHY Control "},
|
||
+ {MV_PHY_STATUS, "PHY Status "},
|
||
+ {MV_PHY_ID1, "PHY Identifier 1 "},
|
||
+ {MV_PHY_ID2, "PHY Identifier 2 "},
|
||
+ {MV_AUTONEG_ADVERT, "Auto-Negotiation Advertisement "},
|
||
+ {MV_LINK_PARTNER_ABILITY, "Link Partner Ability "},
|
||
+ {MV_AUTONEG_EXPANSION, "Auto-Negotiation Expansion "},
|
||
+ {MV_NEXT_PAGE_TRANSMIT, "Next Page Transmit "},
|
||
+ {MV_LINK_PARTNER_NEXT_PAGE, "Link Partner Next Page "},
|
||
+ {MV_PHY_SPECIFIC_CONTROL_1, "PHY-Specific Control Register 1 "},
|
||
+ {MV_PHY_SPECIFIC_STATUS, "PHY-Specific Status "},
|
||
+ {MV_PHY_INTERRUPT_ENABLE, "PHY Interrupt Enable "},
|
||
+ {MV_PHY_INTERRUPT_STATUS, "PHY Interrupt Status "},
|
||
+ {MV_PHY_INTERRUPT_PORT_SUMMARY, "PHY Interrupt Port Summary "},
|
||
+ {MV_RECEIVE_ERROR_COUNTER, "Receive Error Counter "},
|
||
+ {MV_LED_PARALLEL_SELECT, "LED Parallel Select "},
|
||
+ {MV_LED_STREAM_SELECT_LEDS, "LED Stream Select "},
|
||
+ {MV_PHY_LED_CONTROL, "PHY LED Control "},
|
||
+ {MV_PHY_MANUAL_LED_OVERRIDE, "PHY Manual LED Override "},
|
||
+ {MV_VCT_CONTROL, "VCT Control "},
|
||
+ {MV_VCT_STATUS, "VCT Status "},
|
||
+ {MV_PHY_SPECIFIC_CONTROL_2, "PHY-Specific Control Register 2 "},
|
||
+};
|
||
+int mvPhyNumRegs = sizeof(mvPhyRegisterTable) / sizeof(mvPhyRegisterTable[0]);
|
||
+
|
||
+
|
||
+mvRegisterTableEntry_t mvSwitchPortRegisterTable[] = {
|
||
+ {MV_PORT_STATUS, "Port Status "},
|
||
+ {MV_SWITCH_ID, "Switch ID "},
|
||
+ {MV_PORT_CONTROL, "Port Control "},
|
||
+ {MV_PORT_BASED_VLAN_MAP, "Port-Based VLAN Map "},
|
||
+ {MV_PORT_ASSOCIATION_VECTOR, "Port Association Vector "},
|
||
+ {MV_RX_COUNTER, "RX Counter "},
|
||
+ {MV_TX_COUNTER, "TX Counter "},
|
||
+};
|
||
+int mvSwitchPortNumRegs =
|
||
+ sizeof(mvSwitchPortRegisterTable) / sizeof(mvSwitchPortRegisterTable[0]);
|
||
+
|
||
+
|
||
+mvRegisterTableEntry_t mvSwitchGlobalRegisterTable[] = {
|
||
+ {MV_SWITCH_GLOBAL_STATUS, "Switch Global Status "},
|
||
+ {MV_SWITCH_MAC_ADDR0, "Switch MAC Addr 0 & 1 "},
|
||
+ {MV_SWITCH_MAC_ADDR2, "Switch MAC Addr 2 & 3 "},
|
||
+ {MV_SWITCH_MAC_ADDR4, "Switch MAC Addr 4 & 5 "},
|
||
+ {MV_SWITCH_GLOBAL_CONTROL, "Switch Global Control "},
|
||
+ {MV_ATU_CONTROL, "ATU Control "},
|
||
+ {MV_ATU_OPERATION, "ATU Operation "},
|
||
+ {MV_ATU_DATA, "ATU Data "},
|
||
+ {MV_ATU_MAC_ADDR0, "ATU MAC Addr 0 & 1 "},
|
||
+ {MV_ATU_MAC_ADDR2, "ATU MAC Addr 2 & 3 "},
|
||
+ {MV_ATU_MAC_ADDR4, "ATU MAC Addr 4 & 5 "},
|
||
+};
|
||
+int mvSwitchGlobalNumRegs =
|
||
+ sizeof(mvSwitchGlobalRegisterTable) / sizeof(mvSwitchGlobalRegisterTable[0]);
|
||
+
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_phyShow - Dump the state of a PHY.
|
||
+* There are two sets of registers for each phy port:
|
||
+* "phy registers" and
|
||
+* "switch port registers"
|
||
+* We dump 'em all, plus the switch global registers.
|
||
+*/
|
||
+void
|
||
+mv_phyShow(int phyUnit)
|
||
+{
|
||
+ int i;
|
||
+ UINT16 value;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+ UINT32 switchPortAddr;
|
||
+
|
||
+ if (!mv_validPhyId(phyUnit)) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
|
||
+
|
||
+ PRINTF("PHY state for PHY%d (ethmac%d, phyBase 0x%8x, phyAddr 0x%x, switchAddr 0x%x)\n",
|
||
+ phyUnit,
|
||
+ MV_ETHUNIT(phyUnit),
|
||
+ MV_PHYBASE(phyUnit),
|
||
+ MV_PHYADDR(phyUnit),
|
||
+ MV_SWITCH_PORT_ADDR(phyUnit));
|
||
+
|
||
+ PRINTF("PHY Registers:\n");
|
||
+ for (i=0; i < mvPhyNumRegs; i++) {
|
||
+
|
||
+ value = phyRegRead(phyBase, phyAddr, mvPhyRegisterTable[i].regNum);
|
||
+
|
||
+ PRINTF("Reg %02d (0x%02x) %s = 0x%08x\n",
|
||
+ mvPhyRegisterTable[i].regNum,
|
||
+ mvPhyRegisterTable[i].regNum,
|
||
+ mvPhyRegisterTable[i].regIdString,
|
||
+ value);
|
||
+ }
|
||
+
|
||
+ PRINTF("Switch Port Registers:\n");
|
||
+ for (i=0; i < mvSwitchPortNumRegs; i++) {
|
||
+
|
||
+ value = phyRegRead(phyBase, switchPortAddr,
|
||
+ mvSwitchPortRegisterTable[i].regNum);
|
||
+
|
||
+ PRINTF("Reg %02d (0x%02x) %s = 0x%08x\n",
|
||
+ mvSwitchPortRegisterTable[i].regNum,
|
||
+ mvSwitchPortRegisterTable[i].regNum,
|
||
+ mvSwitchPortRegisterTable[i].regIdString,
|
||
+ value);
|
||
+ }
|
||
+
|
||
+ PRINTF("Switch Global Registers:\n");
|
||
+ for (i=0; i < mvSwitchGlobalNumRegs; i++) {
|
||
+
|
||
+ value = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
|
||
+ mvSwitchGlobalRegisterTable[i].regNum);
|
||
+
|
||
+ PRINTF("Reg %02d (0x%02x) %s = 0x%08x\n",
|
||
+ mvSwitchGlobalRegisterTable[i].regNum,
|
||
+ mvSwitchGlobalRegisterTable[i].regNum,
|
||
+ mvSwitchGlobalRegisterTable[i].regIdString,
|
||
+ value);
|
||
+ }
|
||
+}
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_phySet - Modify the value of a PHY register (debug only).
|
||
+*/
|
||
+void
|
||
+mv_phySet(int phyUnit, UINT32 regnum, UINT32 value)
|
||
+{
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ if (mv_validPhyId(phyUnit)) {
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ phyAddr = MV_PHYADDR(phyUnit);
|
||
+
|
||
+ phyRegWrite(phyBase, phyAddr, regnum, value);
|
||
+ }
|
||
+}
|
||
+
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_switchPortSet - Modify the value of a switch port register (debug only).
|
||
+*/
|
||
+void
|
||
+mv_switchPortSet(int phyUnit, UINT32 regnum, UINT32 value)
|
||
+{
|
||
+ UINT32 phyBase;
|
||
+ UINT32 switchPortAddr;
|
||
+
|
||
+ if (mv_validPhyId(phyUnit)) {
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
|
||
+
|
||
+ phyRegWrite(phyBase, switchPortAddr, regnum, value);
|
||
+ }
|
||
+}
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_switchGlobalSet - Modify the value of a switch global register
|
||
+* (debug only).
|
||
+*/
|
||
+void
|
||
+mv_switchGlobalSet(int phyUnit, UINT32 regnum, UINT32 value)
|
||
+{
|
||
+ UINT32 phyBase;
|
||
+
|
||
+ if (mv_validPhyId(phyUnit)) {
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, regnum, value);
|
||
+ }
|
||
+}
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_showATUDB - Dump the contents of the Address Translation Unit DataBase
|
||
+* for the PHY switch associated with the specified phy.
|
||
+*/
|
||
+void
|
||
+mv_showATUDB(int phyUnit)
|
||
+{
|
||
+ UINT32 phyBase;
|
||
+ UINT16 ATUData;
|
||
+ UINT16 ATUMac0;
|
||
+ UINT16 ATUMac2;
|
||
+ UINT16 ATUMac4;
|
||
+ int portVec;
|
||
+ int entryState;
|
||
+
|
||
+ if (!mv_validPhyId(phyUnit)) {
|
||
+ PRINTF("Invalid port number: %d\n", phyUnit);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+
|
||
+ /* Wait for previous operation (if any) to complete */
|
||
+ mv_waitWhileATUBusy(phyBase);
|
||
+
|
||
+ /* Initialize ATU MAC to all 1's */
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR0, 0xffff);
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR2, 0xffff);
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR4, 0xffff);
|
||
+
|
||
+ PRINTF(" MAC ADDRESS EntryState PortVector\n");
|
||
+
|
||
+ for(;;) {
|
||
+ /* Tell hardware to get next MAC info */
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_OPERATION,
|
||
+ MV_ATU_OP_GET_NEXT | MV_ATU_IS_BUSY);
|
||
+
|
||
+ mv_waitWhileATUBusy(phyBase);
|
||
+
|
||
+ ATUData = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_DATA);
|
||
+ entryState = (ATUData & MV_ENTRYSTATE_MASK) >> MV_ENTRYSTATE_SHIFT;
|
||
+
|
||
+ if (entryState == 0) {
|
||
+ /* We've hit the end of the list */
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ ATUMac0 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR0);
|
||
+ ATUMac2 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR2);
|
||
+ ATUMac4 = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR, MV_ATU_MAC_ADDR4);
|
||
+
|
||
+ portVec = (ATUData & MV_PORTVEC_MASK) >> MV_PORTVEC_SHIFT;
|
||
+
|
||
+ PRINTF("%02x:%02x:%02x:%02x:%02x:%02x 0x%02x 0x%02x\n",
|
||
+ ATUMac0 >> 8, /* MAC byte 0 */
|
||
+ ATUMac0 & 0xff, /* MAC byte 1 */
|
||
+ ATUMac2 >> 8, /* MAC byte 2 */
|
||
+ ATUMac2 & 0xff, /* MAC byte 3 */
|
||
+ ATUMac4 >> 8, /* MAC byte 4 */
|
||
+ ATUMac4 & 0xff, /* MAC byte 5 */
|
||
+ entryState,
|
||
+ portVec);
|
||
+ }
|
||
+}
|
||
+
|
||
+LOCAL BOOL countingGoodFrames;
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_countGoodFrames - starts counting GOOD RX/TX frames per port
|
||
+*/
|
||
+void
|
||
+mv_countGoodFrames(int phyUnit)
|
||
+{
|
||
+ UINT32 phyBase;
|
||
+ UINT16 globalControl;
|
||
+
|
||
+ if (mv_validPhyId(phyUnit)) {
|
||
+ /*
|
||
+ * Guarantee that counters are cleared by
|
||
+ * forcing CtrMode to toggle and end on GOODFRAMES.
|
||
+ */
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+
|
||
+ /* Read current Switch Global Control Register */
|
||
+ globalControl = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
|
||
+ MV_SWITCH_GLOBAL_CONTROL);
|
||
+
|
||
+ /* Set CtrMode to count BAD frames */
|
||
+ globalControl = ((globalControl & ~MV_CTRMODE_MASK) |
|
||
+ MV_CTRMODE_BADFRAMES);
|
||
+
|
||
+ /* Push new value out to hardware */
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR,
|
||
+ MV_SWITCH_GLOBAL_CONTROL, globalControl);
|
||
+
|
||
+ /* Now toggle CtrMode to count GOOD frames */
|
||
+ globalControl = ((globalControl & ~MV_CTRMODE_MASK) |
|
||
+ MV_CTRMODE_GOODFRAMES);
|
||
+
|
||
+ /* Push new value out to hardware */
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR,
|
||
+ MV_SWITCH_GLOBAL_CONTROL, globalControl);
|
||
+
|
||
+ countingGoodFrames = TRUE;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_countBadFrames - starts counting BAD RX/TX frames per port
|
||
+*/
|
||
+void
|
||
+mv_countBadFrames(int phyUnit)
|
||
+{
|
||
+ UINT32 phyBase;
|
||
+ UINT16 globalControl;
|
||
+
|
||
+ if (mv_validPhyId(phyUnit)) {
|
||
+ /*
|
||
+ * Guarantee that counters are cleared by
|
||
+ * forcing CtrMode to toggle and end on BADFRAMES.
|
||
+ */
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+
|
||
+ /* Read current Switch Global Control Register */
|
||
+ globalControl = phyRegRead(phyBase, MV_SWITCH_GLOBAL_ADDR,
|
||
+ MV_SWITCH_GLOBAL_CONTROL);
|
||
+
|
||
+ /* Set CtrMode to count GOOD frames */
|
||
+ globalControl = ((globalControl & ~MV_CTRMODE_MASK) |
|
||
+ MV_CTRMODE_GOODFRAMES);
|
||
+
|
||
+ /* Push new value out to hardware */
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR,
|
||
+ MV_SWITCH_GLOBAL_CONTROL, globalControl);
|
||
+
|
||
+ /* Now toggle CtrMode to count BAD frames */
|
||
+ globalControl = ((globalControl & ~MV_CTRMODE_MASK) |
|
||
+ MV_CTRMODE_BADFRAMES);
|
||
+
|
||
+ /* Push new value out to hardware */
|
||
+ phyRegWrite(phyBase, MV_SWITCH_GLOBAL_ADDR,
|
||
+ MV_SWITCH_GLOBAL_CONTROL, globalControl);
|
||
+
|
||
+ countingGoodFrames = FALSE;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* mv_showFrameCounts - shows current GOOD/BAD Frame counts
|
||
+*/
|
||
+void
|
||
+mv_showFrameCounts(int phyUnit)
|
||
+{
|
||
+ UINT16 rxCounter;
|
||
+ UINT16 txCounter;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 switchPortAddr;
|
||
+
|
||
+ if (!mv_validPhyId(phyUnit)) {
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ phyBase = MV_PHYBASE(phyUnit);
|
||
+ switchPortAddr = MV_SWITCH_PORT_ADDR(phyUnit);
|
||
+
|
||
+ rxCounter = phyRegRead(phyBase, switchPortAddr, MV_RX_COUNTER);
|
||
+
|
||
+ txCounter = phyRegRead(phyBase, switchPortAddr, MV_TX_COUNTER);
|
||
+
|
||
+ PRINTF("port%d %s frames: receive: %05d transmit: %05d\n",
|
||
+ phyUnit,
|
||
+ (countingGoodFrames ? "good" : "error"),
|
||
+ rxCounter,
|
||
+ txCounter);
|
||
+}
|
||
+#endif
|
||
diff -urN linux-2.4.32.new/arch/mips/ar531x/mvPhy.h linux-2.4.32.new-eth/arch/mips/ar531x/mvPhy.h
|
||
--- linux-2.4.32.new/arch/mips/ar531x/mvPhy.h 1970-01-01 01:00:00.000000000 +0100
|
||
+++ linux-2.4.32.new-eth/arch/mips/ar531x/mvPhy.h 2005-12-25 11:54:39.775382608 +0000
|
||
@@ -0,0 +1,160 @@
|
||
+/*
|
||
+ * This file is subject to the terms and conditions of the GNU General Public
|
||
+ * License. See the file "COPYING" in the main directory of this archive
|
||
+ * for more details.
|
||
+ *
|
||
+ * Copyright <20> 2003 Atheros Communications, Inc., All Rights Reserved.
|
||
+ */
|
||
+
|
||
+/*
|
||
+ * mvPhy.h - definitions for the ethernet PHY -- Marvell 88E6060
|
||
+ * All definitions in this file are operating system independent!
|
||
+ */
|
||
+
|
||
+#ifndef MVPHY_H
|
||
+#define MVPHY_H
|
||
+
|
||
+/*****************/
|
||
+/* PHY Registers */
|
||
+/*****************/
|
||
+#define MV_PHY_CONTROL 0
|
||
+#define MV_PHY_STATUS 1
|
||
+#define MV_PHY_ID1 2
|
||
+#define MV_PHY_ID2 3
|
||
+#define MV_AUTONEG_ADVERT 4
|
||
+#define MV_LINK_PARTNER_ABILITY 5
|
||
+#define MV_AUTONEG_EXPANSION 6
|
||
+#define MV_NEXT_PAGE_TRANSMIT 7
|
||
+#define MV_LINK_PARTNER_NEXT_PAGE 8
|
||
+#define MV_PHY_SPECIFIC_CONTROL_1 16
|
||
+#define MV_PHY_SPECIFIC_STATUS 17
|
||
+#define MV_PHY_INTERRUPT_ENABLE 18
|
||
+#define MV_PHY_INTERRUPT_STATUS 19
|
||
+#define MV_PHY_INTERRUPT_PORT_SUMMARY 20
|
||
+#define MV_RECEIVE_ERROR_COUNTER 21
|
||
+#define MV_LED_PARALLEL_SELECT 22
|
||
+#define MV_LED_STREAM_SELECT_LEDS 23
|
||
+#define MV_PHY_LED_CONTROL 24
|
||
+#define MV_PHY_MANUAL_LED_OVERRIDE 25
|
||
+#define MV_VCT_CONTROL 26
|
||
+#define MV_VCT_STATUS 27
|
||
+#define MV_PHY_SPECIFIC_CONTROL_2 28
|
||
+
|
||
+/* MV_PHY_CONTROL fields */
|
||
+#define MV_CTRL_SOFTWARE_RESET 0x8000
|
||
+#define MV_CTRL_AUTONEGOTIATION_ENABLE 0x1000
|
||
+
|
||
+/* MV_PHY_ID1 fields */
|
||
+#define MV_PHY_ID1_EXPECTATION 0x0141 /* OUI >> 6 */
|
||
+
|
||
+/* MV_PHY_ID2 fields */
|
||
+#define MV_OUI_LSB_MASK 0xfc00
|
||
+#define MV_OUI_LSB_EXPECTATION 0x0c00
|
||
+#define MV_OUI_LSB_SHIFT 10
|
||
+#define MV_MODEL_NUM_MASK 0x03f0
|
||
+#define MV_MODEL_NUM_SHIFT 4
|
||
+#define MV_REV_NUM_MASK 0x000f
|
||
+#define MV_REV_NUM_SHIFT 0
|
||
+
|
||
+/* MV_PHY_SPECIFIC_STATUS fields */
|
||
+#define MV_STATUS_RESOLVED_SPEED_100 0x4000
|
||
+#define MV_STATUS_RESOLVED_DUPLEX_FULL 0x2000
|
||
+#define MV_STATUS_RESOLVED 0x0800
|
||
+#define MV_STATUS_REAL_TIME_LINK_UP 0x0400
|
||
+
|
||
+/* Check if autonegotiation is complete and link is up */
|
||
+#define MV_AUTONEG_DONE(mv_phy_specific_status) \
|
||
+ (((mv_phy_specific_status) & \
|
||
+ (MV_STATUS_RESOLVED | MV_STATUS_REAL_TIME_LINK_UP)) == \
|
||
+ (MV_STATUS_RESOLVED | MV_STATUS_REAL_TIME_LINK_UP))
|
||
+
|
||
+
|
||
+/*************************/
|
||
+/* Switch Port Registers */
|
||
+/*************************/
|
||
+#define MV_PORT_STATUS 0
|
||
+#define MV_SWITCH_ID 3
|
||
+#define MV_PORT_CONTROL 4
|
||
+#define MV_PORT_BASED_VLAN_MAP 6
|
||
+#define MV_PORT_ASSOCIATION_VECTOR 11
|
||
+#define MV_RX_COUNTER 16
|
||
+#define MV_TX_COUNTER 17
|
||
+
|
||
+/* MV_SWITCH_ID fields */
|
||
+#define MV_SWITCH_ID_DEV_MASK 0xfff0
|
||
+#define MV_SWITCH_ID_DEV_EXPECTATION 0x0600
|
||
+#define MV_SWITCH_ID_DEV_SHIFT 4
|
||
+#define MV_SWITCH_ID_REV_MASK 0x000f
|
||
+#define MV_SWITCH_ID_REV_SHIFT 0
|
||
+
|
||
+/* MV_PORT_CONTROL fields */
|
||
+#define MV_PORT_CONTROL_PORT_STATE_MASK 0x0003
|
||
+#define MV_PORT_CONTROL_PORT_STATE_DISABLED 0x0000
|
||
+#define MV_PORT_CONTROL_PORT_STATE_FORWARDING 0x0003
|
||
+
|
||
+#define MV_PORT_CONTROL_EGRESS_MODE 0x0100 /* Receive */
|
||
+#define MV_PORT_CONTROL_INGRESS_TRAILER 0x4000 /* Transmit */
|
||
+
|
||
+#define MV_EGRESS_TRAILER_VALID 0x80
|
||
+#define MV_INGRESS_TRAILER_OVERRIDE 0x80
|
||
+
|
||
+#define MV_PHY_TRAILER_SIZE 4
|
||
+
|
||
+
|
||
+/***************************/
|
||
+/* Switch Global Registers */
|
||
+/***************************/
|
||
+#define MV_SWITCH_GLOBAL_STATUS 0
|
||
+#define MV_SWITCH_MAC_ADDR0 1
|
||
+#define MV_SWITCH_MAC_ADDR2 2
|
||
+#define MV_SWITCH_MAC_ADDR4 3
|
||
+#define MV_SWITCH_GLOBAL_CONTROL 4
|
||
+#define MV_ATU_CONTROL 10
|
||
+#define MV_ATU_OPERATION 11
|
||
+#define MV_ATU_DATA 12
|
||
+#define MV_ATU_MAC_ADDR0 13
|
||
+#define MV_ATU_MAC_ADDR2 14
|
||
+#define MV_ATU_MAC_ADDR4 15
|
||
+
|
||
+/* MV_SWITCH_GLOBAL_STATUS fields */
|
||
+#define MV_SWITCH_STATUS_READY_MASK 0x0800
|
||
+
|
||
+/* MV_SWITCH_GLOBAL_CONTROL fields */
|
||
+#define MV_CTRMODE_MASK 0x0100
|
||
+#define MV_CTRMODE_GOODFRAMES 0x0000
|
||
+#define MV_CTRMODE_BADFRAMES 0x0100
|
||
+
|
||
+/* MV_ATU_CONTROL fields */
|
||
+#define MV_ATUCTRL_ATU_LEARNDIS 0x4000
|
||
+#define MV_ATUCTRL_ATU_SIZE_MASK 0x3000
|
||
+#define MV_ATUCTRL_ATU_SIZE_SHIFT 12
|
||
+#define MV_ATUCTRL_ATU_SIZE_DEFAULT 2 /* 1024 entry database */
|
||
+#define MV_ATUCTRL_AGE_TIME_MASK 0x0ff0
|
||
+#define MV_ATUCTRL_AGE_TIME_SHIFT 4
|
||
+#define MV_ATUCTRL_AGE_TIME_DEFAULT 19 /* 19 * 16 = 304 seconds */
|
||
+
|
||
+/* MV_ATU_OPERATION fields */
|
||
+#define MV_ATU_BUSY_MASK 0x8000
|
||
+#define MV_ATU_IS_BUSY 0x8000
|
||
+#define MV_ATU_IS_FREE 0x0000
|
||
+#define MV_ATU_OP_MASK 0x7000
|
||
+#define MV_ATU_OP_FLUSH_ALL 0x1000
|
||
+#define MV_ATU_OP_GET_NEXT 0x4000
|
||
+
|
||
+/* MV_ATU_DATA fields */
|
||
+#define MV_ENTRYPRI_MASK 0xc000
|
||
+#define MV_ENTRYPRI_SHIFT 14
|
||
+#define MV_PORTVEC_MASK 0x03f0
|
||
+#define MV_PORTVEC_SHIFT 4
|
||
+#define MV_ENTRYSTATE_MASK 0x000f
|
||
+#define MV_ENTRYSTATE_SHIFT 0
|
||
+
|
||
+/* PHY Address for the switch itself */
|
||
+#define MV_SWITCH_GLOBAL_ADDR 0x1f
|
||
+
|
||
+BOOL mv_phySetup(int ethUnit, UINT32 phyBase);
|
||
+void mv_phyCheckStatusChange(int ethUnit);
|
||
+BOOL mv_phyIsSpeed100(int ethUnit);
|
||
+BOOL mv_phyIsFullDuplex(int ethUnit);
|
||
+
|
||
+#endif /* MVPHY_H */
|
||
diff -urN linux-2.4.32.new/arch/mips/ar531x/rtPhy.c linux-2.4.32.new-eth/arch/mips/ar531x/rtPhy.c
|
||
--- linux-2.4.32.new/arch/mips/ar531x/rtPhy.c 1970-01-01 01:00:00.000000000 +0100
|
||
+++ linux-2.4.32.new-eth/arch/mips/ar531x/rtPhy.c 2005-12-25 11:54:46.086423184 +0000
|
||
@@ -0,0 +1,272 @@
|
||
+/*
|
||
+ * This file is subject to the terms and conditions of the GNU General Public
|
||
+ * License. See the file "COPYING" in the main directory of this archive
|
||
+ * for more details.
|
||
+ *
|
||
+ * Copyright <20> 2003 Atheros Communications, Inc., All Rights Reserved.
|
||
+ */
|
||
+
|
||
+/*
|
||
+ * Manage the ethernet PHY.
|
||
+ * This code supports a simple 1-port ethernet phy, Realtek RTL8201BL,
|
||
+ * and compatible PHYs, such as the Kendin KS8721B.
|
||
+ * All definitions in this file are operating system independent!
|
||
+ */
|
||
+
|
||
+#if defined(linux)
|
||
+#include <linux/config.h>
|
||
+#include <linux/types.h>
|
||
+#include <linux/netdevice.h>
|
||
+#include <linux/etherdevice.h>
|
||
+#include <linux/delay.h>
|
||
+
|
||
+#include "ar531xlnx.h"
|
||
+#endif
|
||
+
|
||
+#if defined(__ECOS)
|
||
+#include "ae531xecos.h"
|
||
+#endif
|
||
+
|
||
+
|
||
+#include "ae531xmac.h"
|
||
+#include "ae531xreg.h"
|
||
+#include "rtPhy.h"
|
||
+
|
||
+#if /* DEBUG */ 1
|
||
+#define RT_DEBUG_ERROR 0x00000001
|
||
+#define RT_DEBUG_PHYSETUP 0x00000002
|
||
+#define RT_DEBUG_PHYCHANGE 0x00000004
|
||
+
|
||
+int rtPhyDebug = RT_DEBUG_ERROR;
|
||
+
|
||
+#define RT_PRINT(FLG, X) \
|
||
+{ \
|
||
+ if (rtPhyDebug & (FLG)) { \
|
||
+ DEBUG_PRINTF X; \
|
||
+ } \
|
||
+}
|
||
+#else
|
||
+#define RT_PRINT(FLG, X)
|
||
+#endif
|
||
+
|
||
+/*
|
||
+ * Track per-PHY port information.
|
||
+ */
|
||
+typedef struct {
|
||
+ BOOL phyAlive; /* last known state of link */
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+} rtPhyInfo_t;
|
||
+
|
||
+#define ETH_PHY_ADDR 1
|
||
+
|
||
+/*
|
||
+ * This table defines the mapping from phy units to
|
||
+ * per-PHY information.
|
||
+ *
|
||
+ * This table is somewhat board-dependent.
|
||
+ */
|
||
+rtPhyInfo_t rtPhyInfo[] = {
|
||
+ {phyAlive: FALSE, /* PHY 0 */
|
||
+ phyBase: 0, /* filled in by rt_phySetup */
|
||
+ phyAddr: ETH_PHY_ADDR},
|
||
+
|
||
+ {phyAlive: FALSE, /* PHY 1 */
|
||
+ phyBase: 0, /* filled in by rt_phySetup */
|
||
+ phyAddr: ETH_PHY_ADDR}
|
||
+};
|
||
+
|
||
+/* Convert from phy unit# to (phyBase, phyAddr) pair */
|
||
+#define RT_PHYBASE(phyUnit) (rtPhyInfo[phyUnit].phyBase)
|
||
+#define RT_PHYADDR(phyUnit) (rtPhyInfo[phyUnit].phyAddr)
|
||
+
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* rt_phySetup - reset and setup the PHY associated with
|
||
+* the specified MAC unit number.
|
||
+*
|
||
+* Resets the associated PHY port.
|
||
+*
|
||
+* RETURNS:
|
||
+* TRUE --> associated PHY is alive
|
||
+* FALSE --> no LINKs on this ethernet unit
|
||
+*/
|
||
+
|
||
+BOOL
|
||
+rt_phySetup(int ethUnit, UINT32 phyBase)
|
||
+{
|
||
+ BOOL linkAlive = FALSE;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ RT_PHYBASE(ethUnit) = phyBase;
|
||
+
|
||
+ phyAddr = RT_PHYADDR(ethUnit);
|
||
+
|
||
+ /* Reset phy */
|
||
+ phyRegWrite(phyBase, phyAddr, GEN_ctl, PHY_SW_RST | AUTONEGENA);
|
||
+
|
||
+ sysMsDelay(1500);
|
||
+
|
||
+ return linkAlive;
|
||
+}
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* rt_phyIsDuplexFull - Determines whether the phy ports associated with the
|
||
+* specified device are FULL or HALF duplex.
|
||
+*
|
||
+* RETURNS:
|
||
+* TRUE --> FULL
|
||
+* FALSE --> HALF
|
||
+*/
|
||
+BOOL
|
||
+rt_phyIsFullDuplex(int ethUnit)
|
||
+{
|
||
+ UINT16 phyCtl;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ phyBase = RT_PHYBASE(ethUnit);
|
||
+ phyAddr = RT_PHYADDR(ethUnit);
|
||
+
|
||
+ phyCtl = phyRegRead(phyBase, phyAddr, GEN_ctl);
|
||
+
|
||
+ if (phyCtl & DUPLEX) {
|
||
+ return TRUE;
|
||
+ } else {
|
||
+ return FALSE;
|
||
+ }
|
||
+}
|
||
+
|
||
+/******************************************************************************
|
||
+*
|
||
+* rt_phyIsSpeed100 - Determines the speed of phy ports associated with the
|
||
+* specified device.
|
||
+*
|
||
+* RETURNS:
|
||
+* TRUE --> 100Mbit
|
||
+* FALSE --> 10Mbit
|
||
+*/
|
||
+BOOL
|
||
+rt_phyIsSpeed100(int phyUnit)
|
||
+{
|
||
+ UINT16 phyLpa;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ phyBase = RT_PHYBASE(phyUnit);
|
||
+ phyAddr = RT_PHYADDR(phyUnit);
|
||
+
|
||
+ phyLpa = phyRegRead(phyBase, phyAddr, AN_lpa);
|
||
+
|
||
+ if (phyLpa & (LPA_TXFD | LPA_TX)) {
|
||
+ return TRUE;
|
||
+ } else {
|
||
+ return FALSE;
|
||
+ }
|
||
+}
|
||
+
|
||
+/*****************************************************************************
|
||
+*
|
||
+* rt_phyCheckStatusChange -- checks for significant changes in PHY state.
|
||
+*
|
||
+* A "significant change" is:
|
||
+* dropped link (e.g. ethernet cable unplugged) OR
|
||
+* autonegotiation completed + link (e.g. ethernet cable plugged in)
|
||
+*
|
||
+* On AR5311, there is a 1-to-1 mapping of ethernet units to PHYs.
|
||
+* When a PHY is plugged in, phyLinkGained is called.
|
||
+* When a PHY is unplugged, phyLinkLost is called.
|
||
+*/
|
||
+void
|
||
+rt_phyCheckStatusChange(int ethUnit)
|
||
+{
|
||
+ UINT16 phyHwStatus;
|
||
+ rtPhyInfo_t *lastStatus = &rtPhyInfo[ethUnit];
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ phyBase = RT_PHYBASE(ethUnit);
|
||
+ phyAddr = RT_PHYADDR(ethUnit);
|
||
+
|
||
+ phyHwStatus = phyRegRead(phyBase, phyAddr, GEN_sts);
|
||
+
|
||
+ if (lastStatus->phyAlive) { /* last known status was ALIVE */
|
||
+ /* See if we've lost link */
|
||
+ if (!(phyHwStatus & LINK)) {
|
||
+ RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link down\n", ethUnit));
|
||
+ lastStatus->phyAlive = FALSE;
|
||
+ phyLinkLost(ethUnit);
|
||
+ }
|
||
+ } else { /* last known status was DEAD */
|
||
+ /* Check for AN complete */
|
||
+ if ((phyHwStatus & (AUTOCMPLT | LINK)) == (AUTOCMPLT | LINK)) {
|
||
+ RT_PRINT(RT_DEBUG_PHYCHANGE,("\nethmac%d link up\n", ethUnit));
|
||
+ lastStatus->phyAlive = TRUE;
|
||
+ phyLinkGained(ethUnit);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+#if DEBUG
|
||
+
|
||
+/* Define the PHY registers of interest for a phyShow command */
|
||
+struct rtRegisterTable_s {
|
||
+ UINT32 regNum;
|
||
+ char *regIdString;
|
||
+} rtRegisterTable[] =
|
||
+{
|
||
+ {GEN_ctl, "Basic Mode Control (GEN_ctl) "},
|
||
+ {GEN_sts, "Basic Mode Status (GEN_sts) "},
|
||
+ {GEN_id_hi, "PHY Identifier 1 (GET_id_hi) "},
|
||
+ {GEN_id_lo, "PHY Identifier 2 (GET_id_lo) "},
|
||
+ {AN_adv, "Auto-Neg Advertisement (AN_adv) "},
|
||
+ {AN_lpa, "Auto-Neg Link Partner Ability "},
|
||
+ {AN_exp, "Auto-Neg Expansion "},
|
||
+};
|
||
+
|
||
+int rtNumRegs = sizeof(rtRegisterTable) / sizeof(rtRegisterTable[0]);
|
||
+
|
||
+/*
|
||
+ * Dump the state of a PHY.
|
||
+ */
|
||
+void
|
||
+rt_phyShow(int phyUnit)
|
||
+{
|
||
+ int i;
|
||
+ UINT16 value;
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ phyBase = RT_PHYBASE(phyUnit);
|
||
+ phyAddr = RT_PHYADDR(phyUnit);
|
||
+
|
||
+ printf("PHY state for ethphy%d\n", phyUnit);
|
||
+
|
||
+ for (i=0; i<rtNumRegs; i++) {
|
||
+
|
||
+ value = phyRegRead(phyBase, phyAddr, rtRegisterTable[i].regNum);
|
||
+
|
||
+ printf("Reg %02d (0x%02x) %s = 0x%08x\n",
|
||
+ rtRegisterTable[i].regNum, rtRegisterTable[i].regNum,
|
||
+ rtRegisterTable[i].regIdString, value);
|
||
+ }
|
||
+}
|
||
+
|
||
+/*
|
||
+ * Modify the value of a PHY register.
|
||
+ * This makes it a bit easier to modify PHY values during debug.
|
||
+ */
|
||
+void
|
||
+rt_phySet(int phyUnit, UINT32 regnum, UINT32 value)
|
||
+{
|
||
+ UINT32 phyBase;
|
||
+ UINT32 phyAddr;
|
||
+
|
||
+ phyBase = RT_PHYBASE(phyUnit);
|
||
+ phyAddr = RT_PHYADDR(phyUnit);
|
||
+
|
||
+ phyRegWrite(phyBase, phyAddr, regnum, value);
|
||
+}
|
||
+#endif
|
||
diff -urN linux-2.4.32.new/arch/mips/ar531x/rtPhy.h linux-2.4.32.new-eth/arch/mips/ar531x/rtPhy.h
|
||
--- linux-2.4.32.new/arch/mips/ar531x/rtPhy.h 1970-01-01 01:00:00.000000000 +0100
|
||
+++ linux-2.4.32.new-eth/arch/mips/ar531x/rtPhy.h 2005-12-25 11:54:46.089422728 +0000
|
||
@@ -0,0 +1,50 @@
|
||
+/*
|
||
+ * This file is subject to the terms and conditions of the GNU General Public
|
||
+ * License. See the file "COPYING" in the main directory of this archive
|
||
+ * for more details.
|
||
+ *
|
||
+ * Copyright © 2003 Atheros Communications, Inc., All Rights Reserved.
|
||
+ */
|
||
+
|
||
+/*
|
||
+ * rtPhy.h - definitions for the ethernet PHY.
|
||
+ * This code supports a simple 1-port ethernet phy, Realtek RTL8201BL,
|
||
+ * and compatible PHYs, such as the Kendin KS8721B.
|
||
+ * All definitions in this file are operating system independent!
|
||
+ */
|
||
+
|
||
+#ifndef RTPHY_H
|
||
+#define RTPHY_H
|
||
+
|
||
+/* MII Registers */
|
||
+
|
||
+#define GEN_ctl 00
|
||
+#define GEN_sts 01
|
||
+#define GEN_id_hi 02
|
||
+#define GEN_id_lo 03
|
||
+#define AN_adv 04
|
||
+#define AN_lpa 05
|
||
+#define AN_exp 06
|
||
+
|
||
+/* GEN_ctl */
|
||
+#define PHY_SW_RST 0x8000
|
||
+#define LOOPBACK 0x4000
|
||
+#define SPEED 0x2000 /* 100 Mbit/s */
|
||
+#define AUTONEGENA 0x1000
|
||
+#define DUPLEX 0x0100 /* Duplex mode */
|
||
+
|
||
+
|
||
+/* GEN_sts */
|
||
+#define AUTOCMPLT 0x0020 /* Autonegotiation completed */
|
||
+#define LINK 0x0004 /* Link status */
|
||
+
|
||
+/* GEN_ids */
|
||
+#define RT_PHY_ID1_EXPECTATION 0x22
|
||
+
|
||
+/* AN_lpa */
|
||
+#define LPA_TXFD 0x0100 /* Link partner supports 100 TX Full Duplex */
|
||
+#define LPA_TX 0x0080 /* Link partner supports 100 TX Half Duplex */
|
||
+#define LPA_10FD 0x0040 /* Link partner supports 10 BT Full Duplex */
|
||
+#define LPA_10 0x0020 /* Link partner supports 10 BT Half Duplex */
|
||
+
|
||
+#endif /* RTPHY_H */
|