📄 bcm570x.c
字号:
/* * Broadcom BCM570x Ethernet Driver for U-Boot. * Support 5701, 5702, 5703, and 5704. Single instance driver. * Copyright (C) 2002 James F. Dougherty (jfd@broadcom.com) */#include <common.h>#if defined(CONFIG_CMD_NET) \ && (!defined(CONFIG_NET_MULTI)) && defined(CONFIG_BCM570x)#ifdef CONFIG_BMW#include <mpc824x.h>#endif#include <net.h>#include "bcm570x_mm.h"#include "bcm570x_autoneg.h"#include <pci.h>#include <malloc.h>/* * PCI Registers and definitions. */#define PCI_CMD_MASK 0xffff0000 /* mask to save status bits */#define PCI_ANY_ID (~0)/* * PCI memory base for Ethernet device as well as device Interrupt. */#define BCM570X_MBAR 0x80100000#define BCM570X_ILINE 1#define SECOND_USEC 1000000#define MAX_PACKET_SIZE 1600#define MAX_UNITS 4/* Globals to this module */int initialized = 0;unsigned int ioBase = 0;volatile PLM_DEVICE_BLOCK pDevice = NULL; /* 570x softc */volatile PUM_DEVICE_BLOCK pUmDevice = NULL;/* Used to pass the full-duplex flag, etc. */int line_speed[MAX_UNITS] = { 0, 0, 0, 0 };static int full_duplex[MAX_UNITS] = { 1, 1, 1, 1 };static int rx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };static int tx_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };static int auto_flow_control[MAX_UNITS] = { 0, 0, 0, 0 };static int tx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };static int rx_checksum[MAX_UNITS] = { 1, 1, 1, 1 };static int auto_speed[MAX_UNITS] = { 1, 1, 1, 1 };#if JUMBO_FRAMES/* Jumbo MTU for interfaces. */static int mtu[MAX_UNITS] = { 0, 0, 0, 0 };#endif/* Turn on Wake-on lan for a device unit */static int enable_wol[MAX_UNITS] = { 0, 0, 0, 0 };#define TX_DESC_CNT DEFAULT_TX_PACKET_DESC_COUNTstatic unsigned int tx_pkt_desc_cnt[MAX_UNITS] = { TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT, TX_DESC_CNT };#define RX_DESC_CNT DEFAULT_STD_RCV_DESC_COUNTstatic unsigned int rx_std_desc_cnt[MAX_UNITS] = { RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT, RX_DESC_CNT };static unsigned int rx_adaptive_coalesce[MAX_UNITS] = { 1, 1, 1, 1 };#if T3_JUMBO_RCV_RCB_ENTRY_COUNT#define JBO_DESC_CNT DEFAULT_JUMBO_RCV_DESC_COUNTstatic unsigned int rx_jumbo_desc_cnt[MAX_UNITS] = { JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT, JBO_DESC_CNT };#endif#define RX_COAL_TK DEFAULT_RX_COALESCING_TICKSstatic unsigned int rx_coalesce_ticks[MAX_UNITS] = { RX_COAL_TK, RX_COAL_TK, RX_COAL_TK, RX_COAL_TK };#define RX_COAL_FM DEFAULT_RX_MAX_COALESCED_FRAMESstatic unsigned int rx_max_coalesce_frames[MAX_UNITS] = { RX_COAL_FM, RX_COAL_FM, RX_COAL_FM, RX_COAL_FM };#define TX_COAL_TK DEFAULT_TX_COALESCING_TICKSstatic unsigned int tx_coalesce_ticks[MAX_UNITS] = { TX_COAL_TK, TX_COAL_TK, TX_COAL_TK, TX_COAL_TK };#define TX_COAL_FM DEFAULT_TX_MAX_COALESCED_FRAMESstatic unsigned int tx_max_coalesce_frames[MAX_UNITS] = { TX_COAL_FM, TX_COAL_FM, TX_COAL_FM, TX_COAL_FM };#define ST_COAL_TK DEFAULT_STATS_COALESCING_TICKSstatic unsigned int stats_coalesce_ticks[MAX_UNITS] = { ST_COAL_TK, ST_COAL_TK, ST_COAL_TK, ST_COAL_TK };/* * Legitimate values for BCM570x device types */typedef enum { BCM5700VIGIL = 0, BCM5700A6, BCM5700T6, BCM5700A9, BCM5700T9, BCM5700, BCM5701A5, BCM5701T1, BCM5701T8, BCM5701A7, BCM5701A10, BCM5701A12, BCM5701, BCM5702, BCM5703, BCM5703A31, TC996T, TC996ST, TC996SSX, TC996SX, TC996BT, TC997T, TC997SX, TC1000T, TC940BR01, TC942BR01, NC6770, NC7760, NC7770, NC7780} board_t;/* Chip-Rev names for each device-type */static struct { char *name;} chip_rev[] = { { "BCM5700VIGIL"}, { "BCM5700A6"}, { "BCM5700T6"}, { "BCM5700A9"}, { "BCM5700T9"}, { "BCM5700"}, { "BCM5701A5"}, { "BCM5701T1"}, { "BCM5701T8"}, { "BCM5701A7"}, { "BCM5701A10"}, { "BCM5701A12"}, { "BCM5701"}, { "BCM5702"}, { "BCM5703"}, { "BCM5703A31"}, { "TC996T"}, { "TC996ST"}, { "TC996SSX"}, { "TC996SX"}, { "TC996BT"}, { "TC997T"}, { "TC997SX"}, { "TC1000T"}, { "TC940BR01"}, { "TC942BR01"}, { "NC6770"}, { "NC7760"}, { "NC7770"}, { "NC7780"}, { 0}};/* indexed by board_t, above */static struct { char *name;} board_info[] = { { "Broadcom Vigil B5700 1000Base-T"}, { "Broadcom BCM5700 1000Base-T"}, { "Broadcom BCM5700 1000Base-SX"}, { "Broadcom BCM5700 1000Base-SX"}, { "Broadcom BCM5700 1000Base-T"}, { "Broadcom BCM5700"}, { "Broadcom BCM5701 1000Base-T"}, { "Broadcom BCM5701 1000Base-T"}, { "Broadcom BCM5701 1000Base-T"}, { "Broadcom BCM5701 1000Base-SX"}, { "Broadcom BCM5701 1000Base-T"}, { "Broadcom BCM5701 1000Base-T"}, { "Broadcom BCM5701"}, { "Broadcom BCM5702 1000Base-T"}, { "Broadcom BCM5703 1000Base-T"}, { "Broadcom BCM5703 1000Base-SX"}, { "3Com 3C996 10/100/1000 Server NIC"}, { "3Com 3C996 10/100/1000 Server NIC"}, { "3Com 3C996 Gigabit Fiber-SX Server NIC"}, { "3Com 3C996 Gigabit Fiber-SX Server NIC"}, { "3Com 3C996B Gigabit Server NIC"}, { "3Com 3C997 Gigabit Server NIC"}, { "3Com 3C997 Gigabit Fiber-SX Server NIC"}, { "3Com 3C1000 Gigabit NIC"}, { "3Com 3C940 Gigabit LOM (21X21)"}, { "3Com 3C942 Gigabit LOM (31X31)"}, { "Compaq NC6770 Gigabit Server Adapter"}, { "Compaq NC7760 Gigabit Server Adapter"}, { "Compaq NC7770 Gigabit Server Adapter"}, { "Compaq NC7780 Gigabit Server Adapter"}, {0},};/* PCI Devices which use the 570x chipset */struct pci_device_table { unsigned short vendor_id, device_id; /* Vendor/DeviceID */ unsigned short subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ unsigned long board_id; /* Data private to the driver */ int io_size, min_latency;} bcm570xDevices[] = { { 0x14e4, 0x1644, 0x1014, 0x0277, 0, 0, BCM5700VIGIL, 128, 32}, { 0x14e4, 0x1644, 0x14e4, 0x1644, 0, 0, BCM5700A6, 128, 32}, { 0x14e4, 0x1644, 0x14e4, 0x2, 0, 0, BCM5700T6, 128, 32}, { 0x14e4, 0x1644, 0x14e4, 0x3, 0, 0, BCM5700A9, 128, 32}, { 0x14e4, 0x1644, 0x14e4, 0x4, 0, 0, BCM5700T9, 128, 32}, { 0x14e4, 0x1644, 0x1028, 0xd1, 0, 0, BCM5700, 128, 32}, { 0x14e4, 0x1644, 0x1028, 0x0106, 0, 0, BCM5700, 128, 32}, { 0x14e4, 0x1644, 0x1028, 0x0109, 0, 0, BCM5700, 128, 32}, { 0x14e4, 0x1644, 0x1028, 0x010a, 0, 0, BCM5700, 128, 32}, { 0x14e4, 0x1644, 0x10b7, 0x1000, 0, 0, TC996T, 128, 32}, { 0x14e4, 0x1644, 0x10b7, 0x1001, 0, 0, TC996ST, 128, 32}, { 0x14e4, 0x1644, 0x10b7, 0x1002, 0, 0, TC996SSX, 128, 32}, { 0x14e4, 0x1644, 0x10b7, 0x1003, 0, 0, TC997T, 128, 32}, { 0x14e4, 0x1644, 0x10b7, 0x1005, 0, 0, TC997SX, 128, 32}, { 0x14e4, 0x1644, 0x10b7, 0x1008, 0, 0, TC942BR01, 128, 32}, { 0x14e4, 0x1644, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5700, 128, 32}, { 0x14e4, 0x1645, 0x14e4, 1, 0, 0, BCM5701A5, 128, 32}, { 0x14e4, 0x1645, 0x14e4, 5, 0, 0, BCM5701T1, 128, 32}, { 0x14e4, 0x1645, 0x14e4, 6, 0, 0, BCM5701T8, 128, 32}, { 0x14e4, 0x1645, 0x14e4, 7, 0, 0, BCM5701A7, 128, 32}, { 0x14e4, 0x1645, 0x14e4, 8, 0, 0, BCM5701A10, 128, 32}, { 0x14e4, 0x1645, 0x14e4, 0x8008, 0, 0, BCM5701A12, 128, 32}, { 0x14e4, 0x1645, 0x0e11, 0xc1, 0, 0, NC6770, 128, 32}, { 0x14e4, 0x1645, 0x0e11, 0x7c, 0, 0, NC7770, 128, 32}, { 0x14e4, 0x1645, 0x0e11, 0x85, 0, 0, NC7780, 128, 32}, { 0x14e4, 0x1645, 0x1028, 0x0121, 0, 0, BCM5701, 128, 32}, { 0x14e4, 0x1645, 0x10b7, 0x1004, 0, 0, TC996SX, 128, 32}, { 0x14e4, 0x1645, 0x10b7, 0x1006, 0, 0, TC996BT, 128, 32}, { 0x14e4, 0x1645, 0x10b7, 0x1007, 0, 0, TC1000T, 128, 32}, { 0x14e4, 0x1645, 0x10b7, 0x1008, 0, 0, TC940BR01, 128, 32}, { 0x14e4, 0x1645, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5701, 128, 32}, { 0x14e4, 0x1646, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, { 0x14e4, 0x1646, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, { 0x14e4, 0x1646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, { 0x14e4, 0x16a6, 0x14e4, 0x8009, 0, 0, BCM5702, 128, 32}, { 0x14e4, 0x16a6, 0x0e11, 0xbb, 0, 0, NC7760, 128, 32}, { 0x14e4, 0x16a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5702, 128, 32}, { 0x14e4, 0x1647, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, { 0x14e4, 0x1647, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, { 0x14e4, 0x1647, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, { 0x14e4, 0x1647, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, { 0x14e4, 0x1647, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, { 0x14e4, 0x1647, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, { 0x14e4, 0x1647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}, { 0x14e4, 0x16a7, 0x14e4, 0x0009, 0, 0, BCM5703, 128, 32}, { 0x14e4, 0x16a7, 0x14e4, 0x000a, 0, 0, BCM5703A31, 128, 32}, { 0x14e4, 0x16a7, 0x14e4, 0x000b, 0, 0, BCM5703, 128, 32}, { 0x14e4, 0x16a7, 0x14e4, 0x800a, 0, 0, BCM5703, 128, 32}, { 0x14e4, 0x16a7, 0x0e11, 0x9a, 0, 0, NC7770, 128, 32}, { 0x14e4, 0x16a7, 0x0e11, 0x99, 0, 0, NC7780, 128, 32}, { 0x14e4, 0x16a7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5703, 128, 32}};#define n570xDevices (sizeof(bcm570xDevices)/sizeof(bcm570xDevices[0]))/* * Allocate a packet buffer from the bcm570x packet pool. */void *bcm570xPktAlloc (int u, int pksize){ return malloc (pksize);}/* * Free a packet previously allocated from the bcm570x packet * buffer pool. */void bcm570xPktFree (int u, void *p){ free (p);}int bcm570xReplenishRxBuffers (PUM_DEVICE_BLOCK pUmDevice){ PLM_PACKET pPacket; PUM_PACKET pUmPacket; void *skb; int queue_rx = 0; int ret = 0; while ((pUmPacket = (PUM_PACKET) QQ_PopHead (&pUmDevice->rx_out_of_buf_q.Container)) != 0) { pPacket = (PLM_PACKET) pUmPacket; /* reuse an old skb */ if (pUmPacket->skbuff) { QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket); queue_rx = 1; continue; } if ((skb = bcm570xPktAlloc (pUmDevice->index, pPacket->u.Rx.RxBufferSize + 2)) == 0) { QQ_PushHead (&pUmDevice->rx_out_of_buf_q.Container, pPacket); printf ("NOTICE: Out of RX memory.\n"); ret = 1; break; } pUmPacket->skbuff = skb; QQ_PushTail (&pDevice->RxPacketFreeQ.Container, pPacket); queue_rx = 1; } if (queue_rx) { LM_QueueRxPackets (pDevice); } return ret;}/* * Probe, Map, and Init 570x device. */int eth_init (bd_t * bis){ int i, rv, devFound = FALSE; pci_dev_t devbusfn; unsigned short status; /* Find PCI device, if it exists, configure ... */ for (i = 0; i < n570xDevices; i++) { devbusfn = pci_find_device (bcm570xDevices[i].vendor_id, bcm570xDevices[i].device_id, 0); if (devbusfn == -1) { continue; /* No device of that vendor/device ID */ } else { /* Set ILINE */ pci_write_config_byte (devbusfn, PCI_INTERRUPT_LINE, BCM570X_ILINE); /* * 0x10 - 0x14 define one 64-bit MBAR. * 0x14 is the higher-order address bits of the BAR. */ pci_write_config_dword (devbusfn, PCI_BASE_ADDRESS_1, 0); ioBase = BCM570X_MBAR; pci_write_config_dword (devbusfn, PCI_BASE_ADDRESS_0, ioBase); /* * Enable PCI memory, IO, and Master -- don't * reset any status bits in doing so. */ pci_read_config_word (devbusfn, PCI_COMMAND, &status); status |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; pci_write_config_word (devbusfn, PCI_COMMAND, status); printf ("\n%s: bus %d, device %d, function %d: MBAR=0x%x\n", board_info[bcm570xDevices[i].board_id].name, PCI_BUS (devbusfn), PCI_DEV (devbusfn), PCI_FUNC (devbusfn), ioBase); /* Allocate once, but always clear on init */ if (!pDevice) { pDevice = malloc (sizeof (UM_DEVICE_BLOCK)); pUmDevice = (PUM_DEVICE_BLOCK) pDevice; memset (pDevice, 0x0, sizeof (UM_DEVICE_BLOCK)); } /* Configure pci dev structure */ pUmDevice->pdev = devbusfn; pUmDevice->index = 0; pUmDevice->tx_pkt = 0; pUmDevice->rx_pkt = 0; devFound = TRUE; break; } } if (!devFound) { printf ("eth_init: FAILURE: no BCM570x Ethernet devices found.\n"); return -1; } /* Setup defaults for chip */ pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE; if (pDevice->ChipRevId == T3_CHIP_ID_5700_B0) { pDevice->TaskToOffload = LM_TASK_OFFLOAD_NONE; } else { if (rx_checksum[i]) { pDevice->TaskToOffload |= LM_TASK_OFFLOAD_RX_TCP_CHECKSUM | LM_TASK_OFFLOAD_RX_UDP_CHECKSUM; } if (tx_checksum[i]) { pDevice->TaskToOffload |= LM_TASK_OFFLOAD_TX_TCP_CHECKSUM | LM_TASK_OFFLOAD_TX_UDP_CHECKSUM; pDevice->NoTxPseudoHdrChksum = TRUE; } } /* Set Device PCI Memory base address */ pDevice->pMappedMemBase = (PLM_UINT8) ioBase; /* Pull down adapter info */ if ((rv = LM_GetAdapterInfo (pDevice)) != LM_STATUS_SUCCESS) { printf ("bcm570xEnd: LM_GetAdapterInfo failed: rv=%d!\n", rv); return -2; } /* Lock not needed */ pUmDevice->do_global_lock = 0; if (T3_ASIC_REV (pUmDevice->lm_dev.ChipRevId) == T3_ASIC_REV_5700) { /* The 5700 chip works best without interleaved register */ /* accesses on certain machines. */ pUmDevice->do_global_lock = 1; } /* Setup timer delays */ if (T3_ASIC_REV (pDevice->ChipRevId) == T3_ASIC_REV_5701) { pDevice->UseTaggedStatus = TRUE; pUmDevice->timer_interval = CFG_HZ; } else { pUmDevice->timer_interval = CFG_HZ / 50; } /* Grab name .... */ pUmDevice->name = (char *)malloc (strlen (board_info[bcm570xDevices[i].board_id].name) + 1); strcpy (pUmDevice->name, board_info[bcm570xDevices[i].board_id].name); memcpy (pDevice->NodeAddress, bis->bi_enetaddr, 6); LM_SetMacAddress (pDevice, bis->bi_enetaddr); /* Init queues .. */ QQ_InitQueue (&pUmDevice->rx_out_of_buf_q.Container, MAX_RX_PACKET_DESC_COUNT); pUmDevice->rx_last_cnt = pUmDevice->tx_last_cnt = 0; /* delay for 4 seconds */ pUmDevice->delayed_link_ind = (4 * CFG_HZ) / pUmDevice->timer_interval; pUmDevice->adaptive_expiry = CFG_HZ / pUmDevice->timer_interval; /* Sometimes we get spurious ints. after reset when link is down. */ /* This field tells the isr to service the int. even if there is */ /* no status block update. */ pUmDevice->adapter_just_inited = (3 * CFG_HZ) / pUmDevice->timer_interval; /* Initialize 570x */ if (LM_InitializeAdapter (pDevice) != LM_STATUS_SUCCESS) { printf ("ERROR: Adapter initialization failed.\n"); return ERROR; } /* Enable chip ISR */ LM_EnableInterrupt (pDevice); /* Clear MC table */ LM_MulticastClear (pDevice); /* Enable Multicast */ LM_SetReceiveMask (pDevice, pDevice->ReceiveMask | LM_ACCEPT_ALL_MULTICAST); pUmDevice->opened = 1; pUmDevice->tx_full = 0; pUmDevice->tx_pkt = 0; pUmDevice->rx_pkt = 0; printf ("eth%d: %s @0x%lx,", pDevice->index, pUmDevice->name, (unsigned long)ioBase); printf ("node addr "); for (i = 0; i < 6; i++) { printf ("%2.2x", pDevice->NodeAddress[i]); } printf ("\n"); printf ("eth%d: ", pDevice->index); printf ("%s with ", chip_rev[bcm570xDevices[i].board_id].name); if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5400_PHY_ID) printf ("Broadcom BCM5400 Copper "); else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5401_PHY_ID) printf ("Broadcom BCM5401 Copper "); else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5411_PHY_ID) printf ("Broadcom BCM5411 Copper "); else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5701_PHY_ID) printf ("Broadcom BCM5701 Integrated Copper "); else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM5703_PHY_ID) printf ("Broadcom BCM5703 Integrated Copper "); else if ((pDevice->PhyId & PHY_ID_MASK) == PHY_BCM8002_PHY_ID) printf ("Broadcom BCM8002 SerDes "); else if (pDevice->EnableTbi) printf ("Agilent HDMP-1636 SerDes "); else printf ("Unknown "); printf ("transceiver found\n"); printf ("eth%d: %s, MTU: %d,", pDevice->index, pDevice->BusSpeedStr, 1500); if ((pDevice->ChipRevId != T3_CHIP_ID_5700_B0) && rx_checksum[i]) printf ("Rx Checksum ON\n"); else printf ("Rx Checksum OFF\n"); initialized++; return 0;}/* Ethernet Interrupt service routine */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -