blob: f21c4f04c15f4b7f6fae0c065fa5e4904f4da23d [file] [log] [blame]
/*
* drivers/net/big_sur_ge.c - Driver for PMC-Sierra Big Sur
* ethernet ports
*
* Copyright (C) 2003, 2004 PMC-Sierra Inc.
* Author : Manish Lachwani (lachwani@pmc-sierra.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
/*
* This driver also includes the PHY related stuff. The device
* is a fast ethernet device. But, there is a Gigabit unit
* in the works. When that is ready, this driver will support
* it.
*
* Basic Operation
* ================
* The device operates in following modes:
* -> Polled mode, no DMA (FIFO)
* -> Polled mode, Simple DMA
* -> Interrupt mode, Simple DMA
* -> Interrupt mode, Scatter Gather DMA
*
* Scatter Gather DMA does not work. So, we make use of Simple DMA
* mode here. There is no implementation of ring descriptors here
* since it is not working as yet. Note that there could be an enhancement
* whereby the driver can support FIFO mode or Simple DMA. However,
* this version only supports Simple DMA.
*
* Receive Operation
* ==================
* The device DMA's sends an interrupt to the processor. The driver
* is invoked and it determines if the packet is to be received. If
* yes, it allocates a new skb and has the DMA controller transfer the
* data into the newly allocated skb. The receive side handles one
* packet at a time. The Rx FIFO on the device is 2000 bytes.
*
* Send Operation
* ===============
* The device Transmit FIFO is 2000 bytes long, i.e. one packet. When
* sending, the driver makes sure that the packet is aligned. Once
* done, it asks the device to do a DMA transfer from memory to the
* onboard FIFO. The device is stopped till the transfer completes since
* it can DMA only one packet at a time.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/mii.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/irq.h>
#include "big_sur_ge.h"
MODULE_AUTHOR("Manish Lachwani <lachwani@pmc-sierra.com>");
MODULE_DESCRIPTION("PMC-Sierra Big Sur Ethernet MAC Driver");
MODULE_LICENSE("GPL");
#define TX_TIMEOUT (60 * HZ) /* Transmit timeout */
typedef enum DUPLEX { UNKNOWN, HALF_DUPLEX, FULL_DUPLEX } DUPLEX;
/* Big Sur Ethernet MAC structure */
struct big_sur_ge_enet {
struct net_device_stats *stats; /* Statistics for this device */
struct timer_list phy_timer; /* PHY monitoring timer */
u32 index; /* Which interface is this */
u32 save_base_address; /* Saved physical base address */
struct sk_buff *saved_skb; /* skb being transmitted */
spinlock_t lock; /* For atomic access to saved_skb */
u8 mii_addr; /* The MII address of the PHY */
big_sur_ge *emac; /* GE driver structure */
struct tasklet_struct big_sur_tasklet; /* Tasklet structure */
};
extern unsigned char big_sur_mac_addr_base[6];
/*
* Function Prototypes
*/
unsigned long big_sur_ge_dma_control(xdma_channel *);
void big_sur_ge_dma_reset(xdma_channel *);
static void handle_intr(struct net_device *, big_sur_ge *);
void big_sur_ge_check_fifo_recv_error(struct net_device *, big_sur_ge *);
void big_sur_ge_check_fifo_send_error(struct net_device *, big_sur_ge *);
static int big_sur_ge_config_fifo(big_sur_ge *);
static int big_sur_ge_config_dma(big_sur_ge *);
void big_sur_ge_enet_reset(big_sur_ge *);
void big_sur_ge_check_mac_error(big_sur_ge *, unsigned long);
static void big_sur_receive(struct net_device *);
static void big_sur_tx_free_skb(struct net_device *);
big_sur_ge_config *big_sur_ge_get_config(int);
static void big_sur_ge_reset(struct net_device *,DUPLEX);
/*
* DMA Channel Initialization. In case of Simple DMA,
* not much to do here. However, in case of SG DMA, we
* need to intialize the descriptor pointers
*/
int big_sur_ge_dma_init(xdma_channel *dma, unsigned long base_address)
{
dma->reg_base_address = base_address;
dma->ready = 1;
big_sur_ge_dma_reset(dma);
return 0;
}
/*
* Perform the self test on the DMA channel
*/
#define BIG_SUR_GE_CONTROL_REG_RESET_MASK 0x98000000
int big_sur_ge_dma_self_test(xdma_channel *dma)
{
unsigned long reg_data;
big_sur_ge_dma_reset(dma);
reg_data = big_sur_ge_dma_control(dma);
if (reg_data != BIG_SUR_GE_CONTROL_REG_RESET_MASK) {
printk(KERN_ERR "DMA Channel Self Test Failed \n");
return -1;
}
return 0;
}
/*
* Reset the DMA channel
*/
void big_sur_ge_dma_reset(xdma_channel *dma)
{
BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_RST_REG_OFFSET,
BIG_SUR_GE_RESET_MASK);
}
/*
* Get control register from the DMA channel
*/
unsigned long big_sur_ge_dma_control(xdma_channel *dma)
{
return BIG_SUR_GE_READ(dma->reg_base_address + BIG_SUR_GE_DMAC_REG_OFFSET);
}
/*
* Set control register of the DMA channel
*/
void big_sur_ge_set_dma_control(xdma_channel *dma, unsigned long control)
{
BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_DMAC_REG_OFFSET, control);
}
/*
* Get the status of the DMA channel
*/
unsigned long big_sur_ge_dma_status(xdma_channel *dma)
{
return BIG_SUR_GE_READ(dma->reg_base_address + BIG_SUR_GE_DMAS_REG_OFFSET);
}
/*
* Transfer the data over the DMA channel
*/
void big_sur_ge_dma_transfer(xdma_channel *dma, unsigned long *source,
unsigned long *dest, unsigned long length)
{
/* Source Address */
BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_SA_REG_OFFSET,
(unsigned long)source);
/* Destination Address */
BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_DA_REG_OFFSET,
(unsigned long)dest);
/* Length of the data */
BIG_SUR_GE_WRITE(dma->reg_base_address + BIG_SUR_GE_LEN_REG_OFFSET,
length);
}
/*
* Init the packet fifo only in the FIFO mode
*/
int packet_fifo_init(packet_fifo *fifo, u32 reg, u32 data)
{
fifo->reg_base_addr = reg;
fifo->data_base_address = data;
fifo->ready_status = 1;
BIG_SUR_GE_FIFO_RESET(fifo);
return 0;
}
/*
* Write to the packet FIFO, 32-bit at a time.
*/
static int packet_fifo_write(packet_fifo * fifo, int *buffer, int len)
{
unsigned long fifo_count, word_count, extra_byte;
unsigned long *buffer_data = (unsigned long *) buffer;
fifo_count =
BIG_SUR_GE_READ(fifo->reg_base_addr +
BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT);
fifo_count &= BIG_SUR_GE_COUNT_MASK;
word_count = len / BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
extra_byte = len % BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
if (extra_byte > 0)
if (fifo_count > (word_count + 1)) {
printk(KERN_ERR
"No room in the packet send fifo \n");
return -1;
}
for (fifo_count = 0; fifo_count < word_count; fifo_count++)
BIG_SUR_GE_WRITE(fifo->data_base_address,
buffer_data[fifo_count]);
if (extra_byte > 0) {
unsigned long last_word = 0;
int *extra_buffer_data =
(int *) (buffer_data + word_count);
if (extra_byte == 1)
last_word = extra_buffer_data[0] << 24;
else if (extra_byte == 2)
last_word = (extra_buffer_data[0] << 24 |
extra_buffer_data[1] << 16);
else if (extra_byte == 3)
last_word = (extra_buffer_data[0] << 24 |
extra_buffer_data[1] << 16 |
extra_buffer_data[2] << 8);
BIG_SUR_GE_WRITE(fifo->data_base_address, last_word);
}
return 0;
}
/*
* Start transmitting the packet
*/
int big_sur_tx(big_sur_ge *emac, u8 *buffer, unsigned long byte_cnt)
{
unsigned long int_status, reg_data, status_reg;
if ( (!emac->started) && (emac->polled) &&
(emac->dma_sg) )
return -1;
/* There is space in the FIFO */
int_status = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_IISR_OFFSET);
if (int_status & BIG_SUR_GE_EIR_XMIT_LFIFO_FULL_MASK) {
printk(KERN_ERR "Tx FIFO error: Queue is Full \n");
return -1;
}
/*
* Check if there is enough space for this packet
*/
if ((BIG_SUR_GE_GET_COUNT(&emac->send_fifo) * sizeof(unsigned long)) < byte_cnt) {
printk(KERN_ERR "Send FIFO on chip is full \n");
return -1;
}
if (emac->has_dma == 0) {
/* Write to the Send FIFO */
if (packet_fifo_write(&emac->send_fifo, buffer, byte_cnt) == -1) {
printk(KERN_ERR "Error : Could not write to FIFO \n");
return -1;
}
/* Write the MSB of the length */
BIG_SUR_GE_WRITE(emac->base_address + 0x1FF4, (byte_cnt & 0xff00));
/* Write the LSB of the length */
BIG_SUR_GE_WRITE(emac->base_address + 0x1FF8, (byte_cnt & 0x00ff));
/* Write the Status bit */
BIG_SUR_GE_WRITE(emac->base_address + 0x1FFC, 0x80000000);
/* Make sure MAC has done transmitting */
status_reg = BIG_SUR_GE_READ(emac->base_address + 0x1FFC);
while (!(status_reg & 0x80000000)) {
status_reg = BIG_SUR_GE_READ(emac->base_address + 0x1FFC);
if (!(status_reg & 0x80000000))
break;
}
}
else {
/* DMA Engine is not buzy */
if (big_sur_ge_dma_status(&emac->send_channel) & BIG_SUR_GE_DMASR_BUSY_MASK) {
printk(KERN_ERR "Send channel FIFO engine busy \n");
return -1;
}
/* Get ready to transfer the data */
big_sur_ge_set_dma_control(&emac->send_channel,
BIG_SUR_GE_DMACR_SOURCE_INCR_MASK |
BIG_SUR_GE_DMACR_DEST_LOCAL_MASK |
BIG_SUR_GE_DMACR_SG_DISABLE_MASK);
big_sur_ge_dma_transfer(&emac->send_channel, (unsigned long *)buffer,
(unsigned long *)(emac->base_address +
BIG_SUR_GE_PFIFO_TXDATA_OFFSET), byte_cnt);
/* Check the DMA Engine status */
reg_data = big_sur_ge_dma_status(&emac->send_channel);
while (reg_data & BIG_SUR_GE_DMASR_BUSY_MASK) {
reg_data = big_sur_ge_dma_status(&emac->recv_channel);
if (!(reg_data & BIG_SUR_GE_DMASR_BUSY_MASK))
break;
}
/* Check for any DMA errors */
if ( (reg_data & BIG_SUR_GE_DMASR_BUS_ERROR_MASK) ||
(reg_data & BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK)) {
printk(KERN_ERR "Send side DMA error \n");
return -1;
}
/* Write the packet length */
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_TPLR_OFFSET, byte_cnt);
}
/* Good Send */
return 0;
}
/*
* Read the packet FIFO
*/
static int packet_fifo_read(packet_fifo * fifo, u8 * buffer, unsigned int len)
{
unsigned long fifo_count, word_count, extra_byte;
unsigned long *buffer_data = (unsigned long *) buffer;
fifo_count =
BIG_SUR_GE_READ(fifo->reg_base_addr +
BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT);
fifo_count &= BIG_SUR_GE_COUNT_MASK;
if ((fifo_count * BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT) < len)
return -1;
word_count = len / BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
extra_byte = len % BIG_SUR_GE_FIFO_WIDTH_BYTE_COUNT;
for (fifo_count = 0; fifo_count < word_count; fifo_count++)
buffer_data[fifo_count] =
BIG_SUR_GE_READ(fifo->reg_base_addr);
if (extra_byte > 0) {
unsigned long last_word;
int *extra_buffer_data =
(int *) (buffer_data + word_count);
last_word = BIG_SUR_GE_READ(fifo->data_base_address);
if (extra_byte == 1)
extra_buffer_data[0] = (int) (last_word << 24);
else if (extra_byte == 2) {
extra_buffer_data[0] = (int) (last_word << 24);
extra_buffer_data[1] = (int) (last_word << 16);
} else if (extra_byte == 3) {
extra_buffer_data[0] = (int) (last_word << 24);
extra_buffer_data[1] = (int) (last_word << 16);
extra_buffer_data[2] = (int) (last_word << 8);
}
}
return 0;
}
/*
* FIFO receive for Simple DMA case
*/
int big_sur_rx(big_sur_ge *emac, u8 *buffer, unsigned long *byte_cnt)
{
unsigned long int_status, reg_data, packet_length;
if ( (!emac->started) && (emac->polled) &&
(emac->dma_sg) ) {
return -1;
}
/* Not enough space in the current buffer */
if (*byte_cnt < BIG_SUR_GE_MAX_FRAME_SIZE)
return -1;
int_status = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_IISR_OFFSET);
/* FIFO is empty */
if (int_status & BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK) {
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET,
BIG_SUR_GE_EIR_RECV_LFIFO_EMPTY_MASK);
return -1;
}
packet_length = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_RPLR_OFFSET);
if (emac->has_dma == 0) {
reg_data = BIG_SUR_GE_READ(emac->base_address + 0x3FFC);
if (reg_data & 0x80000000) {
if (packet_fifo_read(&emac->recv_fifo, buffer, packet_length) == -1) {
printk(KERN_ERR "Could not read the packet fifo \n");
return -1;
}
BIG_SUR_GE_WRITE(emac->base_address + 0x3FFC, 0x0);
}
}
else {
/* Rx side DMA engine */
if (big_sur_ge_dma_status(&emac->recv_channel) & BIG_SUR_GE_DMASR_BUSY_MASK) {
printk(KERN_ERR "Rx side DMA Engine busy \n");
return -1;
}
if (packet_length == 0) {
printk(KERN_ERR "MAC has the FIFO packet length 0 \n");
return -1;
}
/* For the simple DMA case only */
big_sur_ge_set_dma_control(&emac->recv_channel,
BIG_SUR_GE_DMACR_DEST_INCR_MASK |
BIG_SUR_GE_DMACR_SOURCE_LOCAL_MASK |
BIG_SUR_GE_DMACR_SG_DISABLE_MASK);
big_sur_ge_dma_transfer(&emac->recv_channel, (unsigned long *)
(emac->base_address +
BIG_SUR_GE_PFIFO_RXDATA_OFFSET), (unsigned long *)
buffer, packet_length);
reg_data = big_sur_ge_dma_status(&emac->recv_channel);
while (reg_data & BIG_SUR_GE_DMASR_BUSY_MASK) {
reg_data = big_sur_ge_dma_status(&emac->recv_channel);
if (!(reg_data & BIG_SUR_GE_DMASR_BUSY_MASK))
break;
}
if ( (reg_data & BIG_SUR_GE_DMASR_BUS_ERROR_MASK) ||
(reg_data & BIG_SUR_GE_DMASR_BUS_TIMEOUT_MASK)) {
printk(KERN_ERR "DMA Bus Error \n");
return -1;
}
}
*byte_cnt = packet_length;
return 0;
}
/*
* Main FIFO Interrupt Handler
*/
void big_sur_ge_fifo_intr(unsigned long data)
{
struct net_device *netdev = (struct net_device *)data;
struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
big_sur_ge *emac = (big_sur_ge *)lp->emac;
/* Read the interrupt status */
unsigned long int_status = BIG_SUR_GE_READ(emac->base_address +
XIIF_V123B_DIPR_OFFSET);
/* Handle Rx and Tx */
if (int_status & BIG_SUR_GE_IPIF_EMAC_MASK)
handle_intr(netdev, emac);
/* Handle Receive Error */
if (int_status & BIG_SUR_GE_IPIF_RECV_FIFO_MASK)
big_sur_ge_check_fifo_recv_error(netdev, emac);
/* Handle Transmit Error */
if (int_status & BIG_SUR_GE_IPIF_SEND_FIFO_MASK)
big_sur_ge_check_fifo_send_error(netdev, emac);
/* Clear the errors */
if (int_status & XIIF_V123B_ERROR_MASK)
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DISR_OFFSET,
XIIF_V123B_ERROR_MASK);
}
/*
* Tasklet function to invoke interrupt
*/
void big_sur_tasklet_schedule(void *data)
{
struct net_device *netdev = (struct net_device *)data;
struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
tasklet_schedule(&lp->big_sur_tasklet);
return;
}
/*
* Main intr handler
*/
static void handle_intr(struct net_device *netdev, big_sur_ge *emac)
{
unsigned long int_status = BIG_SUR_GE_READ(emac->base_address +
XIIF_V123B_IISR_OFFSET);
/* Process the Rx side */
if (int_status & BIG_SUR_GE_EIR_RECV_DONE_MASK) {
big_sur_receive(netdev);
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET,
BIG_SUR_GE_EIR_RECV_DONE_MASK);
}
/* Process the Tx side */
if (int_status & BIG_SUR_GE_EIR_XMIT_DONE_MASK) {
big_sur_tx_free_skb(netdev);
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IISR_OFFSET,
BIG_SUR_GE_EIR_XMIT_DONE_MASK);
}
big_sur_ge_check_mac_error(emac, int_status);
}
/*
* For now, the MAC address errors dont trigger a update of the
* stats. There is no stats framework in place. Hence, we just
* check for the errors below and do a reset if needed.
*/
void big_sur_ge_check_mac_error(big_sur_ge *emac, unsigned long int_status)
{
if (int_status & (BIG_SUR_GE_EIR_RECV_DFIFO_OVER_MASK |
BIG_SUR_GE_EIR_RECV_LFIFO_OVER_MASK |
BIG_SUR_GE_EIR_RECV_LFIFO_UNDER_MASK |
BIG_SUR_GE_EIR_RECV_ERROR_MASK |
BIG_SUR_GE_EIR_RECV_MISSED_FRAME_MASK |
BIG_SUR_GE_EIR_RECV_COLLISION_MASK |
BIG_SUR_GE_EIR_RECV_FCS_ERROR_MASK |
BIG_SUR_GE_EIR_RECV_LEN_ERROR_MASK |
BIG_SUR_GE_EIR_RECV_SHORT_ERROR_MASK |
BIG_SUR_GE_EIR_RECV_LONG_ERROR_MASK |
BIG_SUR_GE_EIR_RECV_ALIGN_ERROR_MASK |
BIG_SUR_GE_EIR_XMIT_SFIFO_OVER_MASK |
BIG_SUR_GE_EIR_XMIT_LFIFO_OVER_MASK |
BIG_SUR_GE_EIR_XMIT_SFIFO_UNDER_MASK |
BIG_SUR_GE_EIR_XMIT_LFIFO_UNDER_MASK) ) {
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IIER_OFFSET, 0);
big_sur_ge_enet_reset(emac);
}
}
/*
* Check for FIFO Recv errors
*/
void big_sur_ge_check_fifo_recv_error(struct net_device *netdev, big_sur_ge *emac)
{
if (BIG_SUR_GE_IS_DEADLOCKED(&emac->recv_fifo)) {
unsigned long intr_enable;
/*
* The only way to ack this interrupt is to reset the
* device. However, before we reset, we make sure this
* interrupt is disabled
*/
intr_enable = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_DIER_OFFSET);
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
(intr_enable & ~(BIG_SUR_GE_IPIF_RECV_FIFO_MASK)));
/* Reset the device */
big_sur_ge_reset(netdev, UNKNOWN);
/* Turn the interrupts back on */
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
(intr_enable | BIG_SUR_GE_IPIF_RECV_FIFO_MASK));
}
}
/*
* Check for FIFO Send errors
*/
void big_sur_ge_check_fifo_send_error(struct net_device *netdev, big_sur_ge *emac)
{
if (BIG_SUR_GE_IS_DEADLOCKED(&emac->send_fifo)) {
unsigned long intr_enable;
/* Disable the interrupt first */
intr_enable = BIG_SUR_GE_READ(emac->base_address + XIIF_V123B_DIER_OFFSET);
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
(intr_enable & ~(BIG_SUR_GE_IPIF_SEND_FIFO_MASK)));
/* Reset the device */
big_sur_ge_reset(netdev, UNKNOWN);
/* Turn the interrupts back on */
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
(intr_enable | BIG_SUR_GE_IPIF_SEND_FIFO_MASK));
}
}
/*
* GE unit init
*/
int big_sur_ge_enet_init(big_sur_ge *emac, unsigned int device_id)
{
big_sur_ge_config *config;
int err;
/* Assume that the device has been stopped */
config = big_sur_ge_get_config(device_id);
if (config == NULL)
return -1;
emac->ready = 0;
emac->started = 0;
emac->dma_sg = 0;
emac->has_mii = config->has_mii;
emac->has_mcast_hash_table = 0;
emac->dma_config = config->dma_config;
emac->base_address = config->base_address;
if (big_sur_ge_config_dma(emac) == -1)
return -1;
if (emac->has_dma == 0) {
err = big_sur_ge_config_fifo(emac);
if (err == -1)
return err;
}
/* Now, we know that the FIFO initialized successfully. So, set the ready flag */
emac->ready = 1;
/* Do we need a PHY reset here also. It did cause problems on some boards */
big_sur_ge_enet_reset(emac);
/* PHY reset code. Remove if causes a problem on the board */
big_sur_ge_reset_phy(emac->base_address);
return 0;
}
/*
* Start the GE unit for Tx, Rx and Interrupts
*/
int big_sur_ge_start(big_sur_ge *emac)
{
unsigned long reg_data;
/*
* Basic mode of operation is polled and interrupt mode.
* We disable the polled mode for good. We may use the
* polled mode for Rx NAPI but that does not require all
* the interrupts to be disabled
*/
emac->polled = 0;
/*
* DMA: Three modes of operation - simple, FIFO, SG.
* SG is surely not working and so is kept off using the
* dma_sg flag. Simple and FIFO work. But, we may not use FIFO
* at all. So, we enable the interrupts below
*/
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DIER_OFFSET,
BIG_SUR_GE_IPIF_FIFO_DFT_MASK | XIIF_V123B_ERROR_MASK);
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_IIER_OFFSET,
BIG_SUR_GE_EIR_DFT_FIFO_MASK);
/* Toggle the started flag */
emac->started = 1;
/* Start the Tx and Rx units respectively */
reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
reg_data &= ~(BIG_SUR_GE_ECR_XMIT_RESET_MASK | BIG_SUR_GE_ECR_RECV_RESET_MASK);
reg_data |= (BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_ENABLE_MASK);
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
return 0;
}
/*
* Stop the GE unit
*/
int big_sur_ge_stop(big_sur_ge *emac)
{
unsigned long reg_data;
/* We assume that the device is not already stopped */
if (!emac->started)
return 0;
/* Disable the Tx and Rx unit respectively */
reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
reg_data &= ~(BIG_SUR_GE_ECR_XMIT_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_ENABLE_MASK);
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
/* Disable the interrupts */
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_DGIER_OFFSET, 0);
/* Toggle the started flag */
emac->started = 0;
return 0;
}
/*
* Reset the GE MAC unit
*/
void big_sur_ge_enet_reset(big_sur_ge *emac)
{
unsigned long reg_data;
(void) big_sur_ge_stop(emac);
BIG_SUR_GE_WRITE(emac->base_address + XIIF_V123B_RESETR_OFFSET,
XIIF_V123B_RESET_MASK);
/*
* For now, configure the receiver to not strip off
* FCS and padding since this is not currently supported.
* In the future, just take the default and provide the option
* for the user to change this behavior.
*/
reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
reg_data &= ~(BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK | BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK);
reg_data &= ~(BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK);
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
}
/*
* Set the MAC address of the GE mac unit
*/
int big_sur_ge_set_mac_address(big_sur_ge *emac, unsigned char *addr)
{
unsigned long mac_addr = 0;
/* Device is started and so mac address must be set */
if (emac->started == 1)
return 0;
/* Address High */
mac_addr = ( (addr[0] << 8) | addr[1]);
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_SAH_OFFSET, mac_addr);
/* Address Low */
mac_addr |= ( (addr[2] << 24) | (addr[3] << 16) |
(addr[4] << 8) | addr[5]);
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_SAL_OFFSET, mac_addr);
return 0;
}
/*
* Get the MAC address of the GE MAC unit
*/
void big_sur_ge_get_mac_unit(big_sur_ge *emac, unsigned int *addr)
{
unsigned long mac_addr_hi, mac_addr_lo;
mac_addr_hi = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_SAH_OFFSET);
mac_addr_lo = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_SAL_OFFSET);
addr[0] = (mac_addr_hi >> 8);
addr[1] = mac_addr_hi;
addr[2] = (mac_addr_lo >> 24);
addr[3] = (mac_addr_lo >> 16);
addr[4] = (mac_addr_lo >> 8);
addr[5] = mac_addr_lo;
}
/*
* Configure the GE MAC for DMA capabilities, only Simple
*/
static int big_sur_ge_config_dma(big_sur_ge *emac)
{
/* Supports Simple DMA */
emac->has_dma = 1;
if (big_sur_ge_dma_init(&emac->recv_channel, emac->base_address +
BIG_SUR_GE_DMA_RECV_OFFSET) == -1) {
printk(KERN_ERR "Could not initialize the DMA unit \n");
return -1;
}
if (big_sur_ge_dma_init(&emac->send_channel, emac->base_address +
BIG_SUR_GE_DMA_SEND_OFFSET) == -1) {
printk(KERN_ERR "Could not initialize the DMA unit \n");
return -1;
}
return 0;
}
/*
* Configure the FIFO for simple DMA
*/
static int big_sur_ge_config_fifo(big_sur_ge *emac)
{
int err = 0;
/* Receive side packet FIFO */
err = packet_fifo_init(&emac->recv_fifo, emac->base_address +
BIG_SUR_GE_PFIFO_RXREG_OFFSET, emac->base_address +
BIG_SUR_GE_PFIFO_RXDATA_OFFSET);
if (err == -1) {
printk(KERN_ERR "Could not initialize Rx packet FIFO for Simple DMA \n");
return err;
}
/* Send side Packet FIFO */
err = packet_fifo_init(&emac->send_fifo, emac->base_address +
BIG_SUR_GE_PFIFO_TXREG_OFFSET, emac->base_address +
BIG_SUR_GE_PFIFO_TXDATA_OFFSET);
if (err == -1) {
printk(KERN_ERR "Could not initialize Tx packet FIFO for Simple DMA \n");
}
return err;
}
typedef struct {
unsigned long option;
unsigned long mask;
} option_map;
static option_map option_table[] = {
{BIG_SUR_GE_UNICAST_OPTION, BIG_SUR_GE_ECR_UNICAST_ENABLE_MASK},
{BIG_SUR_GE_BROADCAST_OPTION, BIG_SUR_GE_ECR_BROAD_ENABLE_MASK},
{BIG_SUR_GE_PROMISC_OPTION, BIG_SUR_GE_ECR_PROMISC_ENABLE_MASK},
{BIG_SUR_GE_FDUPLEX_OPTION, BIG_SUR_GE_ECR_FULL_DUPLEX_MASK},
{BIG_SUR_GE_LOOPBACK_OPTION, BIG_SUR_GE_ECR_LOOPBACK_MASK},
{BIG_SUR_GE_MULTICAST_OPTION, BIG_SUR_GE_ECR_MULTI_ENABLE_MASK},
{BIG_SUR_GE_FLOW_CONTROL_OPTION, BIG_SUR_GE_ECR_PAUSE_FRAME_MASK},
{BIG_SUR_GE_INSERT_PAD_OPTION, BIG_SUR_GE_ECR_XMIT_PAD_ENABLE_MASK},
{BIG_SUR_GE_INSERT_FCS_OPTION, BIG_SUR_GE_ECR_XMIT_FCS_ENABLE_MASK},
{BIG_SUR_GE_INSERT_ADDR_OPTION, BIG_SUR_GE_ECR_XMIT_ADDR_INSERT_MASK},
{BIG_SUR_GE_OVWRT_ADDR_OPTION, BIG_SUR_GE_ECR_XMIT_ADDR_OVWRT_MASK},
{BIG_SUR_GE_STRIP_PAD_OPTION, BIG_SUR_GE_ECR_RECV_PAD_ENABLE_MASK},
{BIG_SUR_GE_STRIP_FCS_OPTION, BIG_SUR_GE_ECR_RECV_FCS_ENABLE_MASK},
{BIG_SUR_GE_STRIP_PAD_FCS_OPTION, BIG_SUR_GE_ECR_RECV_STRIP_ENABLE_MASK}
};
#define BIG_SUR_GE_NUM_OPTIONS (sizeof(option_table) / sizeof(option_map))
/*
* Set the options for the GE
*/
int big_sur_ge_set_options(big_sur_ge *emac, unsigned long option_flag)
{
unsigned long reg_data;
unsigned int index;
/* Assume that the device is stopped before calling this function */
reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
for (index = 0; index < BIG_SUR_GE_NUM_OPTIONS; index++) {
if (option_flag & option_table[index].option)
reg_data |= option_table[index].mask;
else
reg_data &= ~(option_table[index].mask);
}
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_ECR_OFFSET, reg_data);
/* No polled option */
emac->polled = 0;
return 0;
}
/*
* Get the options from the GE
*/
unsigned long big_sur_ge_get_options(big_sur_ge *emac)
{
unsigned long option_flag = 0, reg_data;
unsigned int index;
reg_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_ECR_OFFSET);
for (index = 0; index < BIG_SUR_GE_NUM_OPTIONS; index++) {
if (option_flag & option_table[index].option)
reg_data |= option_table[index].mask;
}
return option_flag;
}
/*
* Set the Inter frame gap
*/
int big_sur_ge_set_frame_gap(big_sur_ge *emac, int part1, int part2)
{
unsigned long config;
/* Assume that the device is stopped before calling this */
config = ( (part1 << BIG_SUR_GE_IFGP_PART1_SHIFT) |
(part2 << BIG_SUR_GE_IFGP_PART2_SHIFT) );
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_IFGP_OFFSET, config);
return 0;
}
/*
* Get the Inter frame gap
*/
void big_sur_ge_get_frame_gap(big_sur_ge *emac, int *part1, int *part2)
{
unsigned long config;
config = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_IFGP_OFFSET);
*part1 = ((config & BIG_SUR_GE_IFGP_PART1_SHIFT) >> BIG_SUR_GE_IFGP_PART1_SHIFT);
*part2 = ((config & BIG_SUR_GE_IFGP_PART2_SHIFT) >> BIG_SUR_GE_IFGP_PART2_SHIFT);
}
/*
* PHY specific functions for the MAC
*/
#define BIG_SUR_GE_MAX_PHY_ADDR 32
#define BIG_SUR_GE_MAX_PHY_REG 32
/*
* Read the PHY reg
*/
int big_sur_ge_phy_read(big_sur_ge *emac, unsigned long addr,
unsigned long reg_num, unsigned int *data)
{
unsigned long mii_control, mii_data;
if (!emac->has_mii)
return -1;
mii_control = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET);
if (mii_control & BIG_SUR_GE_MGTCR_START_MASK) {
printk(KERN_ERR "PHY busy \n");
return -1;
}
mii_control = (addr << BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT);
mii_control |= (reg_num << BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT);
mii_control |= (BIG_SUR_GE_MGTCR_RW_NOT_MASK | BIG_SUR_GE_MGTCR_START_MASK |
BIG_SUR_GE_MGTCR_MII_ENABLE_MASK);
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET, mii_control);
while (mii_control & BIG_SUR_GE_MGTCR_START_MASK)
if (!(mii_control & BIG_SUR_GE_MGTCR_START_MASK))
break;
mii_data = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTDR_OFFSET);
*data = (unsigned int) mii_data;
return 0;
}
/*
* Write to the PHY register
*/
int big_sur_ge_phy_write(big_sur_ge *emac, unsigned long addr,
unsigned long reg_num, unsigned int data)
{
unsigned long mii_control;
if (!emac->has_mii)
return -1;
mii_control = BIG_SUR_GE_READ(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET);
if (mii_control & BIG_SUR_GE_MGTCR_START_MASK) {
printk(KERN_ERR "PHY busy \n");
return -1;
}
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTDR_OFFSET, (unsigned long)data);
mii_control = (addr << BIG_SUR_GE_MGTCR_PHY_ADDR_SHIFT);
mii_control |= (reg_num << BIG_SUR_GE_MGTCR_REG_ADDR_SHIFT);
mii_control |= (BIG_SUR_GE_MGTCR_START_MASK | BIG_SUR_GE_MGTCR_MII_ENABLE_MASK);
BIG_SUR_GE_WRITE(emac->base_address + BIG_SUR_GE_MGTCR_OFFSET, mii_control);
while (mii_control & BIG_SUR_GE_MGTCR_START_MASK)
if (!(mii_control & BIG_SUR_GE_MGTCR_START_MASK))
break;
return 0;
}
/*
* Reset the GE system
*/
static void big_sur_ge_reset(struct net_device *netdev, DUPLEX duplex)
{
struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
struct sk_buff *skb;
unsigned long options;
int ifcfg1, ifcfg2;
/* Stop the queue */
netif_stop_queue(netdev);
big_sur_ge_get_frame_gap(lp->emac, &ifcfg1, &ifcfg2);
options = big_sur_ge_get_options(lp->emac);
switch (duplex) {
case HALF_DUPLEX:
options &= ~(BIG_SUR_GE_FDUPLEX_OPTION);
break;
case FULL_DUPLEX:
options |= BIG_SUR_GE_FDUPLEX_OPTION;
break;
case UNKNOWN:
break;
}
big_sur_ge_enet_reset(lp->emac);
/* Set the necessary options for the MAC unit */
big_sur_ge_set_mac_address(lp->emac, netdev->dev_addr);
big_sur_ge_set_frame_gap(lp->emac, ifcfg1, ifcfg2);
big_sur_ge_set_options(lp->emac, options);
(void) big_sur_ge_start(lp->emac);
spin_lock_irq(lp->lock);
skb = lp->saved_skb;
lp->saved_skb = NULL;
spin_unlock_irq(lp->lock);
if (skb)
dev_kfree_skb(skb);
/* Start the queue, in case it was stopped */
netif_wake_queue(netdev);
}
/*
* Get the PHY status and then configure the
* speed, duplex, link status etc.
*/
static int big_sur_ge_get_phy_status(struct net_device *netdev,
DUPLEX *duplex, int *linkup)
{
struct big_sur_ge_enet *lp = netdev->priv;
unsigned int reg_data;
int err = 0;
err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_BMCR, &reg_data);
if (err == -1) {
printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
return err;
}
if (!(reg_data & BMCR_ANENABLE)) {
if (reg_data & BMCR_FULLDPLX)
*duplex = FULL_DUPLEX;
else
*duplex = HALF_DUPLEX;
}
else {
unsigned int advertise, partner, neg;
err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_ADVERTISE, &advertise);
if (err == -1) {
printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
return err;
}
err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_LPA, &partner);
if (err == -1) {
printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
return err;
}
neg = advertise & partner & ADVERTISE_ALL;
if (neg & ADVERTISE_100FULL)
*duplex = FULL_DUPLEX;
else if (neg & ADVERTISE_100HALF)
*duplex = HALF_DUPLEX;
else if (neg & ADVERTISE_10FULL)
*duplex = FULL_DUPLEX;
else
*duplex = HALF_DUPLEX;
err = big_sur_ge_phy_read(lp->emac, lp->mii_addr, MII_BMSR, &reg_data);
if (err == -1) {
printk(KERN_ERR "%s: Could not read PHY control register", netdev->name);
return err;
}
*linkup = (reg_data & BMSR_LSTATUS) != 0;
}
return 0;
}
/*
* Poll the MII for duplex and link status
*/
static void big_sur_ge_poll_mii(unsigned long data)
{
struct net_device *netdev = (struct net_device *) data;
struct big_sur_ge_enet* lp = netdev->priv;
unsigned long options;
DUPLEX mac_duplex, phy_duplex;
int phy_carrier, netif_carrier;
if (big_sur_ge_get_phy_status(netdev, &phy_duplex, &phy_carrier) == -1) {
printk(KERN_ERR "%s: Terminating link monitoring.\n", netdev->name);
return;
}
options = big_sur_ge_get_options(lp->emac);
if (options & BIG_SUR_GE_FDUPLEX_OPTION)
mac_duplex = FULL_DUPLEX;
else
mac_duplex = HALF_DUPLEX;
if (mac_duplex != phy_duplex) {
tasklet_disable(&lp->big_sur_tasklet);
big_sur_ge_reset(netdev, phy_duplex);
tasklet_enable(&lp->big_sur_tasklet);
}
netif_carrier = netif_carrier_ok(netdev) != 0;
if (phy_carrier != netif_carrier) {
if (phy_carrier) {
printk(KERN_INFO "%s: Link carrier restored.\n",
netdev->name);
netif_carrier_on(netdev);
} else {
printk(KERN_INFO "%s: Link carrier lost.\n", netdev->name);
netif_carrier_off(netdev);
}
}
/* Set up the timer so we'll get called again in 2 seconds. */
lp->phy_timer.expires = jiffies + 2 * HZ;
add_timer(&lp->phy_timer);
}
/*
* Open the network interface
*/
static int big_sur_ge_open(struct net_device *netdev)
{
struct big_sur_ge_enet *lp = netdev->priv;
unsigned long options;
DUPLEX phy_duplex, mac_duplex;
int phy_carrier;
(void) big_sur_ge_stop(lp->emac);
if (big_sur_ge_set_mac_address(lp->emac, netdev->dev_addr) == -1) {
printk(KERN_ERR "%s: Could not set MAC address.\n", netdev->name);
return -EIO;
}
options = big_sur_ge_get_options(lp->emac);
/*
* This MAC unit has no support for Interrupts. So, we initialize
* a tasklet here that will be scheduled from the timer
* interrupt handler. Note that we cannot run the receive
* and the transmit functions as part of an interrupt handler. Since,
* this will be disastrous for the timer under load. Hence, tasklet
* is the best way to go
*/
tasklet_init(&lp->big_sur_tasklet, big_sur_ge_fifo_intr, (unsigned long)netdev);
if (!(big_sur_ge_get_phy_status(netdev, &phy_duplex, &phy_carrier))) {
if (options & BIG_SUR_GE_FDUPLEX_OPTION)
mac_duplex = FULL_DUPLEX;
else
mac_duplex = HALF_DUPLEX;
if (mac_duplex != phy_duplex) {
switch (phy_duplex) {
case HALF_DUPLEX:
options &= ~(BIG_SUR_GE_FDUPLEX_OPTION);
break;
case FULL_DUPLEX:
options |= BIG_SUR_GE_FDUPLEX_OPTION;
break;
case UNKNOWN:
break;
}
big_sur_ge_set_options(lp->emac, options);
}
}
if (big_sur_ge_start(lp->emac) == -1) {
printk(KERN_ERR "%s: Could not start device.\n", netdev->name);
tasklet_kill(&lp->big_sur_tasklet);
return -EBUSY;
}
MOD_INC_USE_COUNT;
netif_start_queue(netdev);
lp->phy_timer.expires = jiffies + 2*HZ;
lp->phy_timer.data = (unsigned long)netdev;
lp->phy_timer.function = &big_sur_ge_poll_mii;
add_timer(&lp->phy_timer);
return 0;
}
/*
* Close the network device interface
*/
static int big_sur_ge_close(struct net_device *netdev)
{
struct big_sur_ge_enet *lp = netdev->priv;
del_timer_sync(&lp->phy_timer);
netif_stop_queue(netdev);
if (big_sur_ge_stop(lp->emac) == -1) {
printk(KERN_ERR "%s: Could not stop device.\n", netdev->name);
return -EBUSY;
}
tasklet_kill(&lp->big_sur_tasklet);
MOD_DEC_USE_COUNT;
return 0;
}
/*
* Get the network device stats.
*/
static struct net_device_stats *big_sur_ge_get_stats(struct net_device *netdev)
{
struct big_sur_ge_enet *lp = netdev->priv;
return lp->stats;
}
/*
* FIFO send for a packet that needs to be transmitted
*/
static int big_sur_start_xmit(struct sk_buff *orig_skb, struct net_device *netdev)
{
struct big_sur_ge_enet *lp = netdev->priv;
struct sk_buff *new_skb;
unsigned int len, align;
struct net_device_stats *stats = lp->stats;
/*
* The FIFO takes a single request at a time. Stop the queue to
* accomplish this. We'll wake the queue in the transmit
* routine below or in the timeout routine
*/
netif_stop_queue(netdev);
len = orig_skb->len;
/*
* Align the packet for the FIFO
*/
if (!(new_skb = dev_alloc_skb(len + 4))) {
dev_kfree_skb(orig_skb);
printk(KERN_ERR "%s: Could not allocate transmit buffer.\n",
netdev->name);
netif_wake_queue(netdev);
return -EBUSY;
}
align = 4 - ((unsigned long) new_skb->data & 3);
if (align != 4)
skb_reserve(new_skb, align);
skb_put(new_skb, len);
memcpy(new_skb->data, orig_skb->data, len);
dev_kfree_skb(orig_skb);
lp->saved_skb = new_skb;
/* Do the actual transmit */
if (big_sur_tx(lp->emac, (u8 *) new_skb->data, len) == -1) {
spin_lock_irq(&lp->lock);
new_skb = lp->saved_skb;
lp->saved_skb = NULL;
spin_unlock_irq(&lp->lock);
dev_kfree_skb(new_skb);
printk(KERN_ERR "%s: Could not transmit buffer.\n", netdev->name);
netif_wake_queue(netdev);
return -EIO;
}
stats->tx_bytes += len;
stats->tx_packets++;
return 0;
}
/*
* Free the skb
*/
static void big_sur_tx_free_skb(struct net_device *netdev)
{
struct big_sur_ge_enet *lp = netdev->priv;
struct sk_buff *skb;
spin_lock_irq(&lp->lock);
skb = lp->saved_skb;
lp->saved_skb = NULL;
spin_unlock_irq(&lp->lock);
if (skb)
dev_kfree_skb(skb);
/* Start the queue since we know that packet has been transmitted */
netif_wake_queue(netdev);
}
/*
* Handle the timeout of the ethernet device
*/
static void big_sur_ge_tx_timeout(struct net_device *netdev)
{
struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev;
printk("%s: Exceeded transmit timeout of %lu ms. Resetting mac.\n",
netdev->name, TX_TIMEOUT * 1000UL / HZ);
tasklet_disable(&lp->big_sur_tasklet);
big_sur_ge_reset(netdev, UNKNOWN);
tasklet_enable(&lp->big_sur_tasklet);
}
/*
* Receive the packets
*/
static void big_sur_receive(struct net_device *netdev)
{
struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
struct sk_buff *skb;
unsigned long len = BIG_SUR_GE_MAX_FRAME_SIZE;
unsigned int align;
struct net_device_stats *stats = lp->stats;
if (!(skb = dev_alloc_skb(len + 4))) {
printk(KERN_ERR "%s: Could not allocate receive buffer.\n",
netdev->name);
return;
}
align = 4 - ((unsigned long) skb->data & 3);
if (align != 4)
skb_reserve(skb, align);
if (big_sur_rx(lp->emac, (u8 *)skb->data, &len) == -1) {
dev_kfree_skb(skb);
printk(KERN_ERR "%s: Could not receive buffer \n", netdev->name);
netdev->tx_timeout = NULL;
big_sur_ge_reset(netdev, UNKNOWN);
netdev->tx_timeout = big_sur_ge_tx_timeout;
}
skb_put(skb, len);
skb->dev = netdev;
skb->protocol = eth_type_trans(skb, netdev);
stats->rx_packets++;
stats->rx_bytes += len;
/* Good Rx, send the packet upstream. */
netif_rx(skb);
}
/*
* Set the Multicast Hash list
*/
static void big_sur_ge_set_multi(struct net_device *netdev)
{
struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev->priv;
unsigned long options;
tasklet_disable(&lp->big_sur_tasklet);
(void) big_sur_ge_stop(lp->emac);
options = big_sur_ge_get_options(lp->emac);
options &= ~(BIG_SUR_GE_PROMISC_OPTION | BIG_SUR_GE_MULTICAST_OPTION);
if (netdev->flags & IFF_PROMISC)
options |= BIG_SUR_GE_PROMISC_OPTION;
(void) big_sur_ge_start(lp->emac);
tasklet_enable(&lp->big_sur_tasklet);
}
/*
* IOCTL support
*/
static int big_sur_ge_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
{
struct big_sur_ge_enet *lp = netdev->priv;
struct mii_ioctl_data *data = (struct mii_ioctl_data *) &rq->ifr_data;
switch(cmd) {
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
case SIOCDEVPRIVATE: /* for binary compat, remove in 2.5 */
data->phy_id = lp->mii_addr;
case SIOCGMIIREG: /* Read MII PHY register. */
case SIOCDEVPRIVATE + 1: /* for binary compat, remove in 2.5 */
if (data->phy_id > 31 || data->reg_num > 31)
return -ENXIO;
del_timer_sync(&lp->phy_timer);
if (big_sur_ge_phy_read(lp->emac, data->phy_id,
data->reg_num, &data->val_out) == -1) {
printk(KERN_ERR "%s: Could not read from PHY", netdev->name);
return -EBUSY;
}
lp->phy_timer.expires = jiffies + 2*HZ;
add_timer(&lp->phy_timer);
return 0;
case SIOCSMIIREG: /* Write MII PHY register. */
case SIOCDEVPRIVATE + 2: /* for binary compat, remove in 2.5 */
if (data->phy_id > 31 || data->reg_num > 31)
return -ENXIO;
del_timer_sync(&lp->phy_timer);
if (big_sur_ge_phy_write(lp->emac, data->phy_id, data->reg_num,
data->val_in) == -1) {
printk(KERN_ERR "%s: Could not write to PHY", netdev->name);
return -EBUSY;
}
lp->phy_timer.expires = jiffies + 2*HZ;
add_timer(&lp->phy_timer);
return 0;
default:
return -EOPNOTSUPP;
}
}
/*
* Get the config from the config table
*/
big_sur_ge_config *big_sur_ge_get_config(int index)
{
/* For port 0 only */
big_sur_ge_config *config;
config->device_id = 0;
config->base_address = BIG_SUR_GE_BASE; /* Base Address of the MAC */
config->has_counters = 0;
config->has_sg_dma = 0;
config->dma_config = 0;
config->has_mii = 1;
return (big_sur_ge_config *)config;
}
/*
* Release the network device structure
*/
static void big_sur_ge_remove_dev(struct net_device *netdev)
{
struct big_sur_ge_enet *lp = (struct big_sur_ge_enet *)netdev;
big_sur_ge_config *config;
config = big_sur_ge_get_config(lp->index);
config->base_address = lp->save_base_address;
if (lp->saved_skb)
dev_kfree_skb(lp->saved_skb);
kfree(lp);
unregister_netdev(netdev);
kfree(netdev);
}
/*
* Initial Function to probe the network interface
*/
static int __init big_sur_ge_probe(int index)
{
struct net_device *netdev;
struct big_sur_ge_enet *lp;
big_sur_ge_config *config;
unsigned long maddr;
config = big_sur_ge_get_config(index);
if (!config)
return -ENODEV;
netdev = alloc_etherdev(sizeof(struct big_sur_ge_enet));
if (!netdev) {
printk(KERN_ERR "Could not allocate Big Sur Ethernet device %d.\n",index);
return -ENOMEM;
}
SET_MODULE_OWNER(netdev);
lp = (struct big_sur_ge_enet *)netdev->priv;
memset(lp, 0, sizeof(struct big_sur_ge_enet));
spin_lock_init(&lp->lock);
/* Use KSEG1 address */
lp->save_base_address = config->base_address;
if (big_sur_ge_enet_init(lp->emac, config->device_id) == -1) {
printk(KERN_ERR "%s: Could not initialize device.\n", netdev->name);
big_sur_ge_remove_dev(netdev);
return -ENODEV;
}
memcpy(netdev->dev_addr, big_sur_mac_addr_base, 6);
if (big_sur_ge_set_mac_address(lp->emac, netdev->dev_addr) == -1) {
printk(KERN_ERR "%s: Could not set MAC address.\n", netdev->name);
big_sur_ge_remove_dev(netdev);
return -EIO;
}
/* Check the PHY */
lp->mii_addr = 0xff;
for (maddr = 0; maddr < 31; maddr++) {
unsigned int reg_data;
if (big_sur_ge_phy_read(lp->emac, maddr, MII_BMCR, &reg_data) == 0) {
lp->mii_addr = maddr;
break;
}
}
if (lp->mii_addr == 0xff) {
lp->mii_addr = 0;
printk(KERN_WARNING
"%s: No PHY detected. Assuming a PHY at address %d.\n",
netdev->name, lp->mii_addr);
}
netdev->open = big_sur_ge_open;
netdev->stop = big_sur_ge_close;
netdev->get_stats = big_sur_ge_get_stats;
netdev->do_ioctl = big_sur_ge_ioctl;
netdev->tx_timeout = big_sur_ge_tx_timeout;
netdev->watchdog_timeo = TX_TIMEOUT;
netdev->hard_start_xmit = big_sur_start_xmit;
netdev->set_multicast_list = big_sur_ge_set_multi;
printk(KERN_INFO
"%s: PMC-Sierra Big Sur Ethernet Device %d at 0x%08X mapped to 0x%08X\n",
netdev->name, index,
lp->save_base_address, config->base_address);
return 0;
}
static int __init big_sur_ge_init(void)
{
int index = 0;
while (big_sur_ge_probe(index++) == 0);
return (index > 1) ? 0 : -ENODEV;
}
static void __init big_sur_ge_cleanup_module(void)
{
/* Nothing to do here */
}
module_init(big_sur_ge_init);
module_exit(big_sur_ge_cleanup_module);