]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[myson] Replace driver for Myson Technology NICs
authorMichael Brown <mcb30@ipxe.org>
Thu, 26 Apr 2012 21:10:54 +0000 (22:10 +0100)
committerMichael Brown <mcb30@ipxe.org>
Fri, 27 Apr 2012 10:46:58 +0000 (11:46 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/net/mtd80x.c [deleted file]
src/drivers/net/myson.c [new file with mode: 0644]
src/drivers/net/myson.h [new file with mode: 0644]
src/include/ipxe/errfile.h

diff --git a/src/drivers/net/mtd80x.c b/src/drivers/net/mtd80x.c
deleted file mode 100644 (file)
index 170b5c5..0000000
+++ /dev/null
@@ -1,1022 +0,0 @@
-/**************************************************************************
-*
-*    mtd80x.c: Etherboot device driver for the mtd80x Ethernet chip.
-*    Written 2004-2004 by Erdem Güven <zuencap@yahoo.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-*    Portions of this code based on:
-*               fealnx.c: A Linux device driver for the mtd80x Ethernet chip
-*               Written 1998-2000 by Donald Becker
-*
-***************************************************************************/
-
-FILE_LICENCE ( GPL2_OR_LATER );
-
-/* to get some global routines like printf */
-#include "etherboot.h"
-/* to get the interface to the body of the program */
-#include "nic.h"
-/* to get the PCI support functions, if this is a PCI NIC */
-#include <ipxe/pci.h>
-#include <ipxe/ethernet.h>
-#include <mii.h>
-
-/* Condensed operations for readability. */
-#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
-#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
-#define get_unaligned(ptr) (*(ptr))
-
-
-/* Operational parameters that are set at compile time. */
-
-/* Keep the ring sizes a power of two for compile efficiency.           */
-/* The compiler will convert <unsigned>'%'<2^N> into a bit mask.        */
-/* Making the Tx ring too large decreases the effectiveness of channel  */
-/* bonding and packet priority.                                         */
-/* There are no ill effects from too-large receive rings.               */
-#define TX_RING_SIZE 2
-#define TX_QUEUE_LEN 10 /* Limit ring entries actually used.  */
-#define RX_RING_SIZE 4
-
-/* Operational parameters that usually are not changed. */
-/* Time in jiffies before concluding the transmitter is hung. */
-#define HZ 100
-#define TX_TIME_OUT   (6*HZ)
-
-/* Allocation size of Rx buffers with normal sized Ethernet frames.
-   Do not change this value without good reason.  This is not a limit,
-   but a way to keep a consistent allocation size among drivers.
- */
-#define PKT_BUF_SZ 1536
-
-/* for different PHY */
-enum phy_type_flags {
-    MysonPHY = 1,
-    AhdocPHY = 2,
-    SeeqPHY = 3,
-    MarvellPHY = 4,
-    Myson981 = 5,
-    LevelOnePHY = 6,
-    OtherPHY = 10,
-};
-
-/* A chip capabilities table*/
-enum chip_capability_flags {
-    HAS_MII_XCVR,
-    HAS_CHIP_XCVR,
-};
-
-#if 0 /* not used */
-static
-struct chip_info
-{
-    u16 dev_id;
-    int flag;
-}
-mtd80x_chips[] = {
-                     {0x0800, HAS_MII_XCVR},
-                     {0x0803, HAS_CHIP_XCVR},
-                     {0x0891, HAS_MII_XCVR}
-                 };
-static int chip_cnt = sizeof( mtd80x_chips ) / sizeof( struct chip_info );
-#endif
-
-/* Offsets to the Command and Status Registers. */
-enum mtd_offsets {
-    PAR0 = 0x0,        /* physical address 0-3 */
-    PAR1 = 0x04,        /* physical address 4-5 */
-    MAR0 = 0x08,        /* multicast address 0-3 */
-    MAR1 = 0x0C,        /* multicast address 4-7 */
-    FAR0 = 0x10,        /* flow-control address 0-3 */
-    FAR1 = 0x14,        /* flow-control address 4-5 */
-    TCRRCR = 0x18,        /* receive & transmit configuration */
-    BCR = 0x1C,        /* bus command */
-    TXPDR = 0x20,        /* transmit polling demand */
-    RXPDR = 0x24,        /* receive polling demand */
-    RXCWP = 0x28,        /* receive current word pointer */
-    TXLBA = 0x2C,        /* transmit list base address */
-    RXLBA = 0x30,        /* receive list base address */
-    ISR = 0x34,        /* interrupt status */
-    IMR = 0x38,        /* interrupt mask */
-    FTH = 0x3C,        /* flow control high/low threshold */
-    MANAGEMENT = 0x40,    /* bootrom/eeprom and mii management */
-    TALLY = 0x44,        /* tally counters for crc and mpa */
-    TSR = 0x48,        /* tally counter for transmit status */
-    BMCRSR = 0x4c,        /* basic mode control and status */
-    PHYIDENTIFIER = 0x50,    /* phy identifier */
-    ANARANLPAR = 0x54,    /* auto-negotiation advertisement and link
-                                                       partner ability */
-    ANEROCR = 0x58,        /* auto-negotiation expansion and pci conf. */
-    BPREMRPSR = 0x5c,    /* bypass & receive error mask and phy status */
-};
-
-/* Bits in the interrupt status/enable registers. */
-/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
-enum intr_status_bits {
-    RFCON = 0x00020000, /* receive flow control xon packet */
-    RFCOFF = 0x00010000, /* receive flow control xoff packet */
-    LSCStatus = 0x00008000, /* link status change */
-    ANCStatus = 0x00004000, /* autonegotiation completed */
-    FBE = 0x00002000, /* fatal bus error */
-    FBEMask = 0x00001800, /* mask bit12-11 */
-    ParityErr = 0x00000000, /* parity error */
-    TargetErr = 0x00001000, /* target abort */
-    MasterErr = 0x00000800, /* master error */
-    TUNF = 0x00000400, /* transmit underflow */
-    ROVF = 0x00000200, /* receive overflow */
-    ETI = 0x00000100, /* transmit early int */
-    ERI = 0x00000080, /* receive early int */
-    CNTOVF = 0x00000040, /* counter overflow */
-    RBU = 0x00000020, /* receive buffer unavailable */
-    TBU = 0x00000010, /* transmit buffer unavilable */
-    TI = 0x00000008, /* transmit interrupt */
-    RI = 0x00000004, /* receive interrupt */
-    RxErr = 0x00000002, /* receive error */
-};
-
-/* Bits in the NetworkConfig register. */
-enum rx_mode_bits {
-    RxModeMask   = 0xe0,
-    AcceptAllPhys = 0x80,        /* promiscuous mode */
-    AcceptBroadcast = 0x40,        /* accept broadcast */
-    AcceptMulticast = 0x20,        /* accept mutlicast */
-    AcceptRunt   = 0x08,        /* receive runt pkt */
-    ALP          = 0x04,        /* receive long pkt */
-    AcceptErr    = 0x02,        /* receive error pkt */
-
-    AcceptMyPhys = 0x00000000,
-    RxEnable     = 0x00000001,
-    RxFlowCtrl   = 0x00002000,
-    TxEnable     = 0x00040000,
-    TxModeFDX    = 0x00100000,
-    TxThreshold  = 0x00e00000,
-
-    PS1000       = 0x00010000,
-    PS10         = 0x00080000,
-    FD           = 0x00100000,
-};
-
-/* Bits in network_desc.status */
-enum rx_desc_status_bits {
-    RXOWN = 0x80000000, /* own bit */
-    FLNGMASK = 0x0fff0000, /* frame length */
-    FLNGShift = 16,
-    MARSTATUS = 0x00004000, /* multicast address received */
-    BARSTATUS = 0x00002000, /* broadcast address received */
-    PHYSTATUS = 0x00001000, /* physical address received */
-    RXFSD = 0x00000800, /* first descriptor */
-    RXLSD = 0x00000400, /* last descriptor */
-    ErrorSummary = 0x80, /* error summary */
-    RUNT = 0x40,  /* runt packet received */
-    LONG = 0x20,  /* long packet received */
-    FAE = 0x10,  /* frame align error */
-    CRC = 0x08,  /* crc error */
-    RXER = 0x04,  /* receive error */
-};
-
-enum rx_desc_control_bits {
-    RXIC = 0x00800000, /* interrupt control */
-    RBSShift = 0,
-};
-
-enum tx_desc_status_bits {
-    TXOWN = 0x80000000, /* own bit */
-    JABTO = 0x00004000, /* jabber timeout */
-    CSL = 0x00002000, /* carrier sense lost */
-    LC = 0x00001000, /* late collision */
-    EC = 0x00000800, /* excessive collision */
-    UDF = 0x00000400, /* fifo underflow */
-    DFR = 0x00000200, /* deferred */
-    HF = 0x00000100, /* heartbeat fail */
-    NCRMask = 0x000000ff, /* collision retry count */
-    NCRShift = 0,
-};
-
-enum tx_desc_control_bits {
-    TXIC = 0x80000000, /* interrupt control */
-    ETIControl = 0x40000000, /* early transmit interrupt */
-    TXLD = 0x20000000, /* last descriptor */
-    TXFD = 0x10000000, /* first descriptor */
-    CRCEnable = 0x08000000, /* crc control */
-    PADEnable = 0x04000000, /* padding control */
-    RetryTxLC = 0x02000000, /* retry late collision */
-    PKTSMask = 0x3ff800, /* packet size bit21-11 */
-    PKTSShift = 11,
-    TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */
-    TBSShift = 0,
-};
-
-/* BootROM/EEPROM/MII Management Register */
-#define MASK_MIIR_MII_READ       0x00000000
-#define MASK_MIIR_MII_WRITE      0x00000008
-#define MASK_MIIR_MII_MDO        0x00000004
-#define MASK_MIIR_MII_MDI        0x00000002
-#define MASK_MIIR_MII_MDC        0x00000001
-
-/* ST+OP+PHYAD+REGAD+TA */
-#define OP_READ             0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */
-#define OP_WRITE            0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */
-
-/* ------------------------------------------------------------------------- */
-/*      Constants for Myson PHY                                              */
-/* ------------------------------------------------------------------------- */
-#define MysonPHYID      0xd0000302
-/* 89-7-27 add, (begin) */
-#define MysonPHYID0     0x0302
-#define StatusRegister  18
-#define SPEED100        0x0400 // bit10
-#define FULLMODE        0x0800 // bit11
-/* 89-7-27 add, (end) */
-
-/* ------------------------------------------------------------------------- */
-/*      Constants for Seeq 80225 PHY                                         */
-/* ------------------------------------------------------------------------- */
-#define SeeqPHYID0      0x0016
-
-#define MIIRegister18   18
-#define SPD_DET_100     0x80
-#define DPLX_DET_FULL   0x40
-
-/* ------------------------------------------------------------------------- */
-/*      Constants for Ahdoc 101 PHY                                          */
-/* ------------------------------------------------------------------------- */
-#define AhdocPHYID0     0x0022
-
-#define DiagnosticReg   18
-#define DPLX_FULL       0x0800
-#define Speed_100       0x0400
-
-/* 89/6/13 add, */
-/* -------------------------------------------------------------------------- */
-/*      Constants                                                             */
-/* -------------------------------------------------------------------------- */
-#define MarvellPHYID0           0x0141
-#define LevelOnePHYID0  0x0013
-
-#define MII1000BaseTControlReg  9
-#define MII1000BaseTStatusReg   10
-#define SpecificReg  17
-
-/* for 1000BaseT Control Register */
-#define PHYAbletoPerform1000FullDuplex  0x0200
-#define PHYAbletoPerform1000HalfDuplex  0x0100
-#define PHY1000AbilityMask              0x300
-
-// for phy specific status register, marvell phy.
-#define SpeedMask       0x0c000
-#define Speed_1000M     0x08000
-#define Speed_100M      0x4000
-#define Speed_10M       0
-#define Full_Duplex     0x2000
-
-// 89/12/29 add, for phy specific status register, levelone phy, (begin)
-#define LXT1000_100M    0x08000
-#define LXT1000_1000M   0x0c000
-#define LXT1000_Full    0x200
-// 89/12/29 add, for phy specific status register, levelone phy, (end)
-
-#if 0
-/* for 3-in-1 case */
-#define PS10            0x00080000
-#define FD              0x00100000
-#define PS1000          0x00010000
-#endif
-
-/* for PHY */
-#define LinkIsUp        0x0004
-#define LinkIsUp2 0x00040000
-
-/* Create a static buffer of size PKT_BUF_SZ for each
-RX and TX Descriptor.  All descriptors point to a
-part of this buffer */
-struct {
-       u8 txb[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned(8)));
-       u8 rxb[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned(8)));
-} mtd80x_bufs __shared;
-#define txb mtd80x_bufs.txb
-#define rxb mtd80x_bufs.rxb
-
-/* The Tulip Rx and Tx buffer descriptors. */
-struct mtd_desc
-{
-    s32 status;
-    s32 control;
-    u32 buffer;
-    u32 next_desc;
-    struct mtd_desc *next_desc_logical;
-    u8* skbuff;
-    u32 reserved1;
-    u32 reserved2;
-};
-
-struct mtd_private
-{
-    struct mtd_desc rx_ring[RX_RING_SIZE];
-    struct mtd_desc tx_ring[TX_RING_SIZE];
-
-    /* Frequently used values: keep some adjacent for cache effect. */
-    int flags;
-    struct pci_dev *pci_dev;
-    unsigned long crvalue;
-    unsigned long bcrvalue;
-    /*unsigned long imrvalue;*/
-    struct mtd_desc *cur_rx;
-    struct mtd_desc *lack_rxbuf;
-    int really_rx_count;
-    struct mtd_desc *cur_tx;
-    struct mtd_desc *cur_tx_copy;
-    int really_tx_count;
-    int free_tx_count;
-    unsigned int rx_buf_sz; /* Based on MTU+slack. */
-
-    /* These values are keep track of the transceiver/media in use. */
-    unsigned int linkok;
-    unsigned int line_speed;
-    unsigned int duplexmode;
-    unsigned int default_port:
-    4; /* Last dev->if_port value. */
-    unsigned int PHYType;
-
-    /* MII transceiver section. */
-    int mii_cnt;  /* MII device addresses. */
-    unsigned char phys[1]; /* MII device addresses. */
-
-    /*other*/
-    const char *nic_name;
-    int ioaddr;
-    u16 dev_id;
-};
-
-static struct mtd_private mtdx;
-
-static int mdio_read(struct nic * , int phy_id, int location);
-static void getlinktype(struct nic * );
-static void getlinkstatus(struct nic * );
-static void set_rx_mode(struct nic *);
-
-/**************************************************************************
- *  init_ring - setup the tx and rx descriptors
- *************************************************************************/
-static void init_ring(struct nic *nic __unused)
-{
-    int i;
-
-    mtdx.cur_rx = &mtdx.rx_ring[0];
-
-    mtdx.rx_buf_sz = PKT_BUF_SZ;
-    /*mtdx.rx_head_desc = &mtdx.rx_ring[0];*/
-
-    /* Initialize all Rx descriptors. */
-    /* Fill in the Rx buffers.  Handle allocation failure gracefully. */
-    for (i = 0; i < RX_RING_SIZE; i++)
-    {
-        mtdx.rx_ring[i].status = RXOWN;
-        mtdx.rx_ring[i].control = mtdx.rx_buf_sz << RBSShift;
-        mtdx.rx_ring[i].next_desc = virt_to_le32desc(&mtdx.rx_ring[i+1]);
-        mtdx.rx_ring[i].next_desc_logical = &mtdx.rx_ring[i+1];
-        mtdx.rx_ring[i].buffer = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]);
-        mtdx.rx_ring[i].skbuff = &rxb[i * PKT_BUF_SZ];
-    }
-    /* Mark the last entry as wrapping the ring. */
-    mtdx.rx_ring[i-1].next_desc = virt_to_le32desc(&mtdx.rx_ring[0]);
-    mtdx.rx_ring[i-1].next_desc_logical = &mtdx.rx_ring[0];
-
-    /* We only use one transmit buffer, but two
-     * descriptors so transmit engines have somewhere
-     * to point should they feel the need */
-    mtdx.tx_ring[0].status = 0x00000000;
-    mtdx.tx_ring[0].buffer = virt_to_bus(&txb[0]);
-    mtdx.tx_ring[0].next_desc = virt_to_le32desc(&mtdx.tx_ring[1]);
-
-    /* This descriptor is never used */
-    mtdx.tx_ring[1].status = 0x00000000;
-    mtdx.tx_ring[1].buffer = 0; /*virt_to_bus(&txb[1]); */
-    mtdx.tx_ring[1].next_desc = virt_to_le32desc(&mtdx.tx_ring[0]);
-
-    return;
-}
-
-/**************************************************************************
-RESET - Reset Adapter
-***************************************************************************/
-static void mtd_reset( struct nic *nic )
-{
-    /* Reset the chip to erase previous misconfiguration. */
-    outl(0x00000001, mtdx.ioaddr + BCR);
-
-    init_ring(nic);
-
-    outl(virt_to_bus(mtdx.rx_ring), mtdx.ioaddr + RXLBA);
-    outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
-
-    /* Initialize other registers. */
-    /* Configure the PCI bus bursts and FIFO thresholds. */
-    mtdx.bcrvalue = 0x10; /* little-endian, 8 burst length */
-    mtdx.crvalue = 0xa00; /* rx 128 burst length */
-
-       if ( mtdx.dev_id == 0x891 ) {
-               mtdx.bcrvalue |= 0x200; /* set PROG bit */
-               mtdx.crvalue |= 0x02000000;     /* set enhanced bit */
-       }
-
-    outl( mtdx.bcrvalue, mtdx.ioaddr + BCR);
-
-    /* Restart Rx engine if stopped. */
-    outl(0, mtdx.ioaddr + RXPDR);
-
-    getlinkstatus(nic);
-    if (mtdx.linkok)
-    {
-        static const char* texts[]={"half","full","10","100","1000"};
-        getlinktype(nic);
-        DBG ( "Link is OK : %s %s\n", texts[mtdx.duplexmode-1], texts[mtdx.line_speed+1] );
-    } else
-    {
-        DBG ( "No link!!!\n" );
-    }
-
-    mtdx.crvalue |= /*TxEnable |*/ RxEnable | TxThreshold;
-    set_rx_mode(nic);
-
-    /* Clear interrupts by setting the interrupt mask. */
-    outl(FBE | TUNF | CNTOVF | RBU | TI | RI, mtdx.ioaddr + ISR);
-    outl( 0, mtdx.ioaddr + IMR);
-}
-
-/**************************************************************************
-POLL - Wait for a frame
-***************************************************************************/
-static int mtd_poll(struct nic *nic, __unused int retrieve)
-{
-    s32 rx_status = mtdx.cur_rx->status;
-    int retval = 0;
-
-    if( ( rx_status & RXOWN ) != 0 )
-    {
-        return 0;
-    }
-
-    if (rx_status & ErrorSummary)
-    { /* there was a fatal error */
-        printf( "%s: Receive error, Rx status %8.8x, Error(s) %s%s%s\n",
-                mtdx.nic_name, (unsigned int) rx_status,
-                (rx_status & (LONG | RUNT)) ? "length_error ":"",
-                (rx_status & RXER) ? "frame_error ":"",
-                (rx_status & CRC) ? "crc_error ":"" );
-        retval = 0;
-    } else if( !((rx_status & RXFSD) && (rx_status & RXLSD)) )
-    {
-        /* this pkt is too long, over one rx buffer */
-        printf("Pkt is too long, over one rx buffer.\n");
-        retval = 0;
-    } else
-    { /* this received pkt is ok */
-        /* Omit the four octet CRC from the length. */
-        short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4;
-
-        DBG ( " netdev_rx() normal Rx pkt length %d"
-             " status %x.\n", pkt_len, (unsigned int) rx_status );
-
-        nic->packetlen = pkt_len;
-        memcpy(nic->packet, mtdx.cur_rx->skbuff, pkt_len);
-
-        retval = 1;
-    }
-
-    while( ( mtdx.cur_rx->status & RXOWN ) == 0 )
-    {
-        mtdx.cur_rx->status = RXOWN;
-        mtdx.cur_rx = mtdx.cur_rx->next_desc_logical;
-    }
-
-    /* Restart Rx engine if stopped. */
-    outl(0, mtdx.ioaddr + RXPDR);
-
-    return retval;
-}
-
-/**************************************************************************
-TRANSMIT - Transmit a frame
-***************************************************************************/
-static void mtd_transmit(
-    struct nic *nic,
-    const char *dest,            /* Destination */
-    unsigned int type,            /* Type */
-    unsigned int size,            /* size */
-    const char *data)            /* Packet */
-{
-    u32 to;
-    u32 tx_status;
-    unsigned int nstype = htons ( type );
-
-    memcpy( txb, dest, ETH_ALEN );
-    memcpy( txb + ETH_ALEN, nic->node_addr, ETH_ALEN );
-    memcpy( txb + 2 * ETH_ALEN, &nstype, 2 );
-    memcpy( txb + ETH_HLEN, data, size );
-
-    size += ETH_HLEN;
-    size &= 0x0FFF;
-    while( size < ETH_ZLEN )
-    {
-        txb[size++] = '\0';
-    }
-
-    mtdx.tx_ring[0].control = TXLD | TXFD | CRCEnable | PADEnable;
-    mtdx.tx_ring[0].control |= (size << PKTSShift); /* pkt size */
-    mtdx.tx_ring[0].control |= (size << TBSShift); /* buffer size */
-    mtdx.tx_ring[0].status = TXOWN;
-
-    /* Point to transmit descriptor */
-    outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA);
-    /* Enable Tx */
-    outl( mtdx.crvalue | TxEnable, mtdx.ioaddr + TCRRCR);
-    /* Wake the potentially-idle transmit channel. */
-    outl(0, mtdx.ioaddr + TXPDR);
-
-    to = currticks() + TX_TIME_OUT;
-    while(( mtdx.tx_ring[0].status & TXOWN) && (currticks() < to));
-
-    /* Disable Tx */
-    outl( mtdx.crvalue & (~TxEnable), mtdx.ioaddr + TCRRCR);
-
-    tx_status = mtdx.tx_ring[0].status;
-    if (currticks() >= to){
-        DBG ( "TX Time Out" );
-    } else if( tx_status & (CSL | LC | EC | UDF | HF)){
-        printf( "Transmit error: %8.8x %s %s %s %s %s\n",
-                (unsigned int) tx_status,
-                tx_status & EC ? "abort" : "",
-                tx_status & CSL ? "carrier" : "",
-                tx_status & LC ? "late" : "",
-                tx_status & UDF ? "fifo" : "",
-                tx_status & HF ? "heartbeat" : "" );
-    }
-
-    /*hex_dump( txb, size );*/
-    /*pause();*/
-
-    DBG ( "TRANSMIT\n" );
-}
-
-/**************************************************************************
-DISABLE - Turn off ethernet interface
-***************************************************************************/
-static void mtd_disable ( struct nic *nic ) {
-
-    /* Disable Tx Rx*/
-    outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR );
-
-    /* Reset the chip to erase previous misconfiguration. */
-    mtd_reset(nic);
-
-    DBG ( "DISABLE\n" );
-}
-
-static struct nic_operations mtd_operations = {
-       .connect        = dummy_connect,
-       .poll           = mtd_poll,
-       .transmit       = mtd_transmit,
-       .irq            = dummy_irq,
-
-};
-
-static struct pci_device_id mtd80x_nics[] = {
-        PCI_ROM(0x1516, 0x0800, "MTD800", "Myson MTD800", 0),
-        PCI_ROM(0x1516, 0x0803, "MTD803", "Surecom EP-320X", 0),
-        PCI_ROM(0x1516, 0x0891, "MTD891", "Myson MTD891", 0),
-};
-
-PCI_DRIVER ( mtd80x_driver, mtd80x_nics, PCI_NO_CLASS );
-
-/**************************************************************************
-PROBE - Look for an adapter, this routine's visible to the outside
-***************************************************************************/
-
-static int mtd_probe ( struct nic *nic, struct pci_device *pci ) {
-
-    int i;
-
-    if (pci->ioaddr == 0)
-           return 0;
-
-    adjust_pci_device(pci);
-
-    nic->ioaddr = pci->ioaddr;
-    nic->irqno = 0;
-
-    mtdx.nic_name = pci->id->name;
-    mtdx.dev_id = pci->device;
-    mtdx.ioaddr = nic->ioaddr;
-
-    /* read ethernet id */
-    for (i = 0; i < 6; ++i)
-    {
-        nic->node_addr[i] = inb(mtdx.ioaddr + PAR0 + i);
-    }
-
-    if (memcmp(nic->node_addr, "\0\0\0\0\0\0", 6) == 0)
-    {
-        return 0;
-    }
-
-    DBG ( "%s: ioaddr %4.4x MAC %s\n", mtdx.nic_name, mtdx.ioaddr, eth_ntoa ( nic->node_addr ) );
-
-    /* Reset the chip to erase previous misconfiguration. */
-    outl(0x00000001, mtdx.ioaddr + BCR);
-
-    /* find the connected MII xcvrs */
-
-    if( mtdx.dev_id != 0x803 )
-    {
-        int phy, phy_idx = 0;
-
-        for (phy = 1; phy < 32 && phy_idx < 1; phy++) {
-            int mii_status = mdio_read(nic, phy, 1);
-
-            if (mii_status != 0xffff && mii_status != 0x0000) {
-                mtdx.phys[phy_idx] = phy;
-
-                DBG ( "%s: MII PHY found at address %d, status "
-                     "0x%4.4x.\n", mtdx.nic_name, phy, mii_status );
-                /* get phy type */
-                {
-                    unsigned int data;
-
-                    data = mdio_read(nic, mtdx.phys[phy_idx], 2);
-                    if (data == SeeqPHYID0)
-                        mtdx.PHYType = SeeqPHY;
-                    else if (data == AhdocPHYID0)
-                        mtdx.PHYType = AhdocPHY;
-                    else if (data == MarvellPHYID0)
-                        mtdx.PHYType = MarvellPHY;
-                    else if (data == MysonPHYID0)
-                        mtdx.PHYType = Myson981;
-                    else if (data == LevelOnePHYID0)
-                        mtdx.PHYType = LevelOnePHY;
-                    else
-                        mtdx.PHYType = OtherPHY;
-                }
-                phy_idx++;
-            }
-        }
-
-        mtdx.mii_cnt = phy_idx;
-        if (phy_idx == 0) {
-            printf("%s: MII PHY not found -- this device may "
-                   "not operate correctly.\n", mtdx.nic_name);
-        }
-    } else {
-        mtdx.phys[0] = 32;
-        /* get phy type */
-        if (inl(mtdx.ioaddr + PHYIDENTIFIER) == MysonPHYID ) {
-            mtdx.PHYType = MysonPHY;
-            DBG ( "MysonPHY\n" );
-        } else {
-            mtdx.PHYType = OtherPHY;
-            DBG ( "OtherPHY\n" );
-        }
-    }
-
-    getlinkstatus(nic);
-    if( !mtdx.linkok )
-    {
-        printf("No link!!!\n");
-        return 0;
-    }
-
-    mtd_reset( nic );
-
-    /* point to NIC specific routines */
-    nic->nic_op        = &mtd_operations;
-    return 1;
-}
-
-
-/**************************************************************************/
-static void set_rx_mode(struct nic *nic __unused)
-{
-    u32 mc_filter[2];                       /* Multicast hash filter */
-    u32 rx_mode;
-
-    /* Too many to match, or accept all multicasts. */
-    mc_filter[1] = mc_filter[0] = ~0;
-    rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
-
-    outl(mc_filter[0], mtdx.ioaddr + MAR0);
-    outl(mc_filter[1], mtdx.ioaddr + MAR1);
-
-    mtdx.crvalue = ( mtdx.crvalue & ~RxModeMask ) | rx_mode;
-    outb( mtdx.crvalue, mtdx.ioaddr + TCRRCR);
-}
-/**************************************************************************/
-static unsigned int m80x_read_tick(void)
-/* function: Reads the Timer tick count register which decrements by 2 from  */
-/*           65536 to 0 every 1/36.414 of a second. Each 2 decrements of the */
-/*           count represents 838 nsec's.                                    */
-/* input   : none.                                                           */
-/* output  : none.                                                           */
-{
-    unsigned char tmp;
-    int value;
-
-    outb((char) 0x06, 0x43); // Command 8254 to latch T0's count
-
-    // now read the count.
-    tmp = (unsigned char) inb(0x40);
-    value = ((int) tmp) << 8;
-    tmp = (unsigned char) inb(0x40);
-    value |= (((int) tmp) & 0xff);
-    return (value);
-}
-
-static void m80x_delay(unsigned int interval)
-/* function: to wait for a specified time.                                   */
-/* input   : interval ... the specified time.                                */
-/* output  : none.                                                           */
-{
-    unsigned int interval1, interval2, i = 0;
-
-    interval1 = m80x_read_tick(); // get initial value
-    do
-    {
-        interval2 = m80x_read_tick();
-        if (interval1 < interval2)
-            interval1 += 65536;
-        ++i;
-    } while (((interval1 - interval2) < (u16) interval) && (i < 65535));
-}
-
-
-static u32 m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad)
-{
-    u32 miir;
-    int i;
-    unsigned int mask, data;
-
-    /* enable MII output */
-    miir = (u32) inl(miiport);
-    miir &= 0xfffffff0;
-
-    miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO;
-
-    /* send 32 1's preamble */
-    for (i = 0; i < 32; i++) {
-        /* low MDC; MDO is already high (miir) */
-        miir &= ~MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-
-        /* high MDC */
-        miir |= MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-    }
-
-    /* calculate ST+OP+PHYAD+REGAD+TA */
-    data = opcode | (phyad << 7) | (regad << 2);
-
-    /* sent out */
-    mask = 0x8000;
-    while (mask) {
-        /* low MDC, prepare MDO */
-        miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
-        if (mask & data)
-            miir |= MASK_MIIR_MII_MDO;
-
-        outl(miir, miiport);
-        /* high MDC */
-        miir |= MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-        m80x_delay(30);
-
-        /* next */
-        mask >>= 1;
-        if (mask == 0x2 && opcode == OP_READ)
-            miir &= ~MASK_MIIR_MII_WRITE;
-    }
-    return miir;
-}
-
-static int mdio_read(struct nic *nic __unused, int phyad, int regad)
-{
-    long miiport = mtdx.ioaddr + MANAGEMENT;
-    u32 miir;
-    unsigned int mask, data;
-
-    miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad);
-
-    /* read data */
-    mask = 0x8000;
-    data = 0;
-    while (mask)
-    {
-        /* low MDC */
-        miir &= ~MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-
-        /* read MDI */
-        miir = inl(miiport);
-        if (miir & MASK_MIIR_MII_MDI)
-            data |= mask;
-
-        /* high MDC, and wait */
-        miir |= MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-        m80x_delay((int) 30);
-
-        /* next */
-        mask >>= 1;
-    }
-
-    /* low MDC */
-    miir &= ~MASK_MIIR_MII_MDC;
-    outl(miir, miiport);
-
-    return data & 0xffff;
-}
-
-#if 0 /* not used */
-static void mdio_write(struct nic *nic __unused, int phyad, int regad,
-                      int data)
-{
-    long miiport = mtdx.ioaddr + MANAGEMENT;
-    u32 miir;
-    unsigned int mask;
-
-    miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad);
-
-    /* write data */
-    mask = 0x8000;
-    while (mask)
-    {
-        /* low MDC, prepare MDO */
-        miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO);
-        if (mask & data)
-            miir |= MASK_MIIR_MII_MDO;
-        outl(miir, miiport);
-
-        /* high MDC */
-        miir |= MASK_MIIR_MII_MDC;
-        outl(miir, miiport);
-
-        /* next */
-        mask >>= 1;
-    }
-
-    /* low MDC */
-    miir &= ~MASK_MIIR_MII_MDC;
-    outl(miir, miiport);
-
-    return;
-}
-#endif
-
-static void getlinkstatus(struct nic *nic)
-/* function: Routine will read MII Status Register to get link status.       */
-/* input   : dev... pointer to the adapter block.                            */
-/* output  : none.                                                           */
-{
-    unsigned int i, DelayTime = 0x1000;
-
-    mtdx.linkok = 0;
-
-    if (mtdx.PHYType == MysonPHY)
-    {
-        for (i = 0; i < DelayTime; ++i) {
-            if (inl(mtdx.ioaddr + BMCRSR) & LinkIsUp2) {
-                mtdx.linkok = 1;
-                return;
-            }
-            // delay
-            m80x_delay(100);
-        }
-    } else
-    {
-        for (i = 0; i < DelayTime; ++i) {
-            if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) {
-                mtdx.linkok = 1;
-                return;
-            }
-            // delay
-            m80x_delay(100);
-        }
-    }
-}
-
-
-static void getlinktype(struct nic *dev)
-{
-    if (mtdx.PHYType == MysonPHY)
-    { /* 3-in-1 case */
-        if (inl(mtdx.ioaddr + TCRRCR) & FD)
-            mtdx.duplexmode = 2; /* full duplex */
-        else
-            mtdx.duplexmode = 1; /* half duplex */
-        if (inl(mtdx.ioaddr + TCRRCR) & PS10)
-            mtdx.line_speed = 1; /* 10M */
-        else
-            mtdx.line_speed = 2; /* 100M */
-    } else
-    {
-        if (mtdx.PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], MIIRegister18);
-            if (data & SPD_DET_100)
-                mtdx.line_speed = 2; /* 100M */
-            else
-                mtdx.line_speed = 1; /* 10M */
-            if (data & DPLX_DET_FULL)
-                mtdx.duplexmode = 2; /* full duplex mode */
-            else
-                mtdx.duplexmode = 1; /* half duplex mode */
-        } else if (mtdx.PHYType == AhdocPHY) {
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], DiagnosticReg);
-            if (data & Speed_100)
-                mtdx.line_speed = 2; /* 100M */
-            else
-                mtdx.line_speed = 1; /* 10M */
-            if (data & DPLX_FULL)
-                mtdx.duplexmode = 2; /* full duplex mode */
-            else
-                mtdx.duplexmode = 1; /* half duplex mode */
-        }
-        /* 89/6/13 add, (begin) */
-        else if (mtdx.PHYType == MarvellPHY) {
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], SpecificReg);
-            if (data & Full_Duplex)
-                mtdx.duplexmode = 2; /* full duplex mode */
-            else
-                mtdx.duplexmode = 1; /* half duplex mode */
-            data &= SpeedMask;
-            if (data == Speed_1000M)
-                mtdx.line_speed = 3; /* 1000M */
-            else if (data == Speed_100M)
-                mtdx.line_speed = 2; /* 100M */
-            else
-                mtdx.line_speed = 1; /* 10M */
-        }
-        /* 89/6/13 add, (end) */
-        /* 89/7/27 add, (begin) */
-        else if (mtdx.PHYType == Myson981) {
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], StatusRegister);
-
-            if (data & SPEED100)
-                mtdx.line_speed = 2;
-            else
-                mtdx.line_speed = 1;
-
-            if (data & FULLMODE)
-                mtdx.duplexmode = 2;
-            else
-                mtdx.duplexmode = 1;
-        }
-        /* 89/7/27 add, (end) */
-        /* 89/12/29 add */
-        else if (mtdx.PHYType == LevelOnePHY) {
-            unsigned int data;
-
-            data = mdio_read(dev, mtdx.phys[0], SpecificReg);
-            if (data & LXT1000_Full)
-                mtdx.duplexmode = 2; /* full duplex mode */
-            else
-                mtdx.duplexmode = 1; /* half duplex mode */
-            data &= SpeedMask;
-            if (data == LXT1000_1000M)
-                mtdx.line_speed = 3; /* 1000M */
-            else if (data == LXT1000_100M)
-                mtdx.line_speed = 2; /* 100M */
-            else
-                mtdx.line_speed = 1; /* 10M */
-        }
-        // chage crvalue
-        // mtdx.crvalue&=(~PS10)&(~FD);
-        mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000);
-        if (mtdx.line_speed == 1)
-            mtdx.crvalue |= PS10;
-        else if (mtdx.line_speed == 3)
-            mtdx.crvalue |= PS1000;
-        if (mtdx.duplexmode == 2)
-            mtdx.crvalue |= FD;
-    }
-}
-
-DRIVER ( "MTD80X", nic_driver, pci_driver, mtd80x_driver,
-        mtd_probe, mtd_disable );
diff --git a/src/drivers/net/myson.c b/src/drivers/net/myson.c
new file mode 100644 (file)
index 0000000..25f1a27
--- /dev/null
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <byteswap.h>
+#include <ipxe/netdevice.h>
+#include <ipxe/ethernet.h>
+#include <ipxe/if_ether.h>
+#include <ipxe/iobuf.h>
+#include <ipxe/malloc.h>
+#include <ipxe/pci.h>
+#include <ipxe/mii.h>
+#include "myson.h"
+
+/** @file
+ *
+ * Myson Technology network card driver
+ *
+ */
+
+/******************************************************************************
+ *
+ * Device reset
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Reset controller chip
+ *
+ * @v myson            Myson device
+ * @ret rc             Return status code
+ */
+static int myson_soft_reset ( struct myson_nic *myson ) {
+       uint32_t bcr;
+       unsigned int i;
+
+       /* Initiate reset */
+       bcr = readl ( myson->regs + MYSON_BCR );
+       writel ( ( bcr | MYSON_BCR_SWR ), myson->regs + MYSON_BCR );
+
+       /* Wait for reset to complete */
+       for ( i = 0 ; i < MYSON_RESET_MAX_WAIT_MS ; i++ ) {
+
+               /* If reset is not complete, delay 1ms and retry */
+               if ( readl ( myson->regs + MYSON_BCR ) & MYSON_BCR_SWR ) {
+                       mdelay ( 1 );
+                       continue;
+               }
+
+               /* Apply a sensible default bus configuration */
+               bcr = readl ( myson->regs + MYSON_BCR );
+               bcr &= ~MYSON_BCR_PBL_MASK;
+               bcr |= ( MYSON_BCR_RLE | MYSON_BCR_RME | MYSON_BCR_WIE |
+                        MYSON_BCR_PBL_DEFAULT );
+               writel ( bcr, myson->regs + MYSON_BCR );
+               DBGC ( myson, "MYSON %p using configuration %08x\n",
+                      myson, bcr );
+
+               return 0;
+       }
+
+       DBGC ( myson, "MYSON %p timed out waiting for reset\n", myson );
+       return -ETIMEDOUT;
+}
+
+/**
+ * Reload configuration from EEPROM
+ *
+ * @v myson            Myson device
+ * @ret rc             Return status code
+ */
+static int myson_reload_config ( struct myson_nic *myson ) {
+       unsigned int i;
+
+       /* Initiate reload */
+       writel ( MYSON_ROM_AUTOLD, myson->regs + MYSON_ROM_MII );
+
+       /* Wait for reload to complete */
+       for ( i = 0 ; i < MYSON_AUTOLD_MAX_WAIT_MS ; i++ ) {
+
+               /* If reload is not complete, delay 1ms and retry */
+               if ( readl ( myson->regs + MYSON_ROM_MII ) & MYSON_ROM_AUTOLD ){
+                       mdelay ( 1 );
+                       continue;
+               }
+
+               return 0;
+       }
+
+       DBGC ( myson, "MYSON %p timed out waiting for configuration "
+              "reload\n", myson );
+       return -ETIMEDOUT;
+}
+
+/**
+ * Reset hardware
+ *
+ * @v myson            Myson device
+ * @ret rc             Return status code
+ */
+static int myson_reset ( struct myson_nic *myson ) {
+       int rc;
+
+       /* Disable all interrupts */
+       writel ( 0, myson->regs + MYSON_IMR );
+
+       /* Perform soft reset */
+       if ( ( rc = myson_soft_reset ( myson ) ) != 0 )
+               return rc;
+
+       /* Reload configuration from EEPROM */
+       if ( ( rc = myson_reload_config ( myson ) ) != 0 )
+               return rc;
+
+       return 0;
+}
+
+/******************************************************************************
+ *
+ * Network device interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Create descriptor ring
+ *
+ * @v myson            Myson device
+ * @v ring             Descriptor ring
+ * @ret rc             Return status code
+ */
+static int myson_create_ring ( struct myson_nic *myson,
+                              struct myson_ring *ring ) {
+       size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
+       struct myson_descriptor *desc;
+       struct myson_descriptor *next;
+       physaddr_t address;
+       unsigned int i;
+       int rc;
+
+       /* Allocate descriptor ring */
+       ring->desc = malloc_dma ( len, MYSON_RING_ALIGN );
+       if ( ! ring->desc ) {
+               rc = -ENOMEM;
+               goto err_alloc;
+       }
+       address = virt_to_bus ( ring->desc );
+
+       /* Check address is usable by card */
+       if ( ! myson_address_ok ( address + len ) ) {
+               DBGC ( myson, "MYSON %p cannot support 64-bit ring address\n",
+                      myson );
+               rc = -ENOTSUP;
+               goto err_64bit;
+       }
+
+       /* Initialise descriptor ring */
+       memset ( ring->desc, 0, len );
+       for ( i = 0 ; i < ring->count ; i++ ) {
+               desc = &ring->desc[i];
+               next = &ring->desc[ ( i + 1 ) % ring->count ];
+               desc->next = cpu_to_le32 ( virt_to_bus ( next ) );
+       }
+
+       /* Program ring address */
+       writel ( address, myson->regs + ring->reg );
+       DBGC ( myson, "MYSON %p ring %02x is at [%08llx,%08llx)\n",
+              myson, ring->reg, ( ( unsigned long long ) address ),
+              ( ( unsigned long long ) address + len ) );
+
+       return 0;
+
+ err_64bit:
+       free_dma ( ring->desc, len );
+       ring->desc = NULL;
+ err_alloc:
+       return rc;
+}
+
+/**
+ * Destroy descriptor ring
+ *
+ * @v myson            Myson device
+ * @v ring             Descriptor ring
+ */
+static void myson_destroy_ring ( struct myson_nic *myson,
+                                struct myson_ring *ring ) {
+       size_t len = ( ring->count * sizeof ( ring->desc[0] ) );
+
+       /* Clear ring address */
+       writel ( 0, myson->regs + ring->reg );
+
+       /* Free descriptor ring */
+       free_dma ( ring->desc, len );
+       ring->desc = NULL;
+       ring->prod = 0;
+       ring->cons = 0;
+}
+
+/**
+ * Refill receive descriptor ring
+ *
+ * @v netdev           Network device
+ */
+static void myson_refill_rx ( struct net_device *netdev ) {
+       struct myson_nic *myson = netdev->priv;
+       struct myson_descriptor *rx;
+       struct io_buffer *iobuf;
+       unsigned int rx_idx;
+       physaddr_t address;
+
+       while ( ( myson->rx.prod - myson->rx.cons ) < MYSON_NUM_RX_DESC ) {
+
+               /* Allocate I/O buffer */
+               iobuf = alloc_iob ( MYSON_RX_MAX_LEN );
+               if ( ! iobuf ) {
+                       /* Wait for next refill */
+                       return;
+               }
+
+               /* Check address is usable by card */
+               address = virt_to_bus ( iobuf->data );
+               if ( ! myson_address_ok ( address ) ) {
+                       DBGC ( myson, "MYSON %p cannot support 64-bit RX "
+                              "buffer address\n", myson );
+                       netdev_rx_err ( netdev, iobuf, -ENOTSUP );
+                       return;
+               }
+
+               /* Get next receive descriptor */
+               rx_idx = ( myson->rx.prod++ % MYSON_NUM_RX_DESC );
+               rx = &myson->rx.desc[rx_idx];
+
+               /* Populate receive descriptor */
+               rx->address = cpu_to_le32 ( address );
+               rx->control =
+                       cpu_to_le32 ( MYSON_RX_CTRL_RBS ( MYSON_RX_MAX_LEN ) );
+               wmb();
+               rx->status = cpu_to_le32 ( MYSON_RX_STAT_OWN );
+               wmb();
+
+               /* Record I/O buffer */
+               assert ( myson->rx_iobuf[rx_idx] == NULL );
+               myson->rx_iobuf[rx_idx] = iobuf;
+
+               /* Notify card that there are descriptors available */
+               writel ( 0, myson->regs + MYSON_RXPDR );
+
+               DBGC2 ( myson, "MYSON %p RX %d is [%llx,%llx)\n", myson,
+                       rx_idx, ( ( unsigned long long ) address ),
+                       ( ( unsigned long long ) address + MYSON_RX_MAX_LEN ) );
+       }
+}
+
+/**
+ * Open network device
+ *
+ * @v netdev           Network device
+ * @ret rc             Return status code
+ */
+static int myson_open ( struct net_device *netdev ) {
+       struct myson_nic *myson = netdev->priv;
+       union myson_physical_address mac;
+       int rc;
+
+       /* Set MAC address */
+       memset ( &mac, 0, sizeof ( mac ) );
+       memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN );
+       writel ( le32_to_cpu ( mac.reg.low ), myson->regs + MYSON_PAR0 );
+       writel ( le32_to_cpu ( mac.reg.high ), myson->regs + MYSON_PAR4 );
+
+       /* Create transmit descriptor ring */
+       if ( ( rc = myson_create_ring ( myson, &myson->tx ) ) != 0 )
+               goto err_create_tx;
+
+       /* Create receive descriptor ring */
+       if ( ( rc = myson_create_ring ( myson, &myson->rx ) ) != 0 )
+               goto err_create_rx;
+
+       /* Configure transmitter and receiver */
+       writel ( ( MYSON_TCR_TE | MYSON_RCR_PROM | MYSON_RCR_AB | MYSON_RCR_AM |
+                  MYSON_RCR_ARP | MYSON_RCR_ALP | MYSON_RCR_RE ),
+                myson->regs + MYSON_TCR_RCR );
+
+       /* Fill receive ring */
+       myson_refill_rx ( netdev );
+
+       return 0;
+
+       myson_destroy_ring ( myson, &myson->rx );
+ err_create_rx:
+       myson_destroy_ring ( myson, &myson->tx );
+ err_create_tx:
+       return rc;
+}
+
+/**
+ * Wait for transmit and receive to become idle
+ *
+ * @v myson            Myson device
+ * @ret rc             Return status code
+ */
+static int myson_wait_idle ( struct myson_nic *myson ) {
+       uint32_t tcr_rcr;
+       unsigned int i;
+
+       /* Wait for both transmit and receive to be idle */
+       for ( i = 0 ; i < MYSON_IDLE_MAX_WAIT_MS ; i++ ) {
+
+               /* If either process is running, delay 1ms and retry */
+               tcr_rcr = readl ( myson->regs + MYSON_TCR_RCR );
+               if ( tcr_rcr & ( MYSON_TCR_TXS | MYSON_RCR_RXS ) ) {
+                       mdelay ( 1 );
+                       continue;
+               }
+
+               return 0;
+       }
+
+       DBGC ( myson, "MYSON %p timed out waiting for idle state (status "
+              "%08x)\n", myson, tcr_rcr );
+       return -ETIMEDOUT;
+}
+
+/**
+ * Close network device
+ *
+ * @v netdev           Network device
+ */
+static void myson_close ( struct net_device *netdev ) {
+       struct myson_nic *myson = netdev->priv;
+       unsigned int i;
+
+       /* Disable receiver and transmitter */
+       writel ( 0, myson->regs + MYSON_TCR_RCR );
+
+       /* Allow time for receiver and transmitter to become idle */
+       myson_wait_idle ( myson );
+
+       /* Destroy receive descriptor ring */
+       myson_destroy_ring ( myson, &myson->rx );
+
+       /* Discard any unused receive buffers */
+       for ( i = 0 ; i < MYSON_NUM_RX_DESC ; i++ ) {
+               if ( myson->rx_iobuf[i] )
+                       free_iob ( myson->rx_iobuf[i] );
+               myson->rx_iobuf[i] = NULL;
+       }
+
+       /* Destroy transmit descriptor ring */
+       myson_destroy_ring ( myson, &myson->tx );
+}
+
+/**
+ * Transmit packet
+ *
+ * @v netdev           Network device
+ * @v iobuf            I/O buffer
+ * @ret rc             Return status code
+ */
+static int myson_transmit ( struct net_device *netdev,
+                           struct io_buffer *iobuf ) {
+       struct myson_nic *myson = netdev->priv;
+       struct myson_descriptor *tx;
+       unsigned int tx_idx;
+       physaddr_t address;
+
+       /* Check address is usable by card */
+       address = virt_to_bus ( iobuf->data );
+       if ( ! myson_address_ok ( address ) ) {
+               DBGC ( myson, "MYSON %p cannot support 64-bit TX buffer "
+                      "address\n", myson );
+               return -ENOTSUP;
+       }
+
+       /* Get next transmit descriptor */
+       if ( ( myson->tx.prod - myson->tx.cons ) >= MYSON_NUM_TX_DESC ) {
+               DBGC ( myson, "MYSON %p out of transmit descriptors\n",
+                      myson );
+               return -ENOBUFS;
+       }
+       tx_idx = ( myson->tx.prod++ % MYSON_NUM_TX_DESC );
+       tx = &myson->tx.desc[tx_idx];
+
+       /* Populate transmit descriptor */
+       tx->address = cpu_to_le32 ( address );
+       tx->control = cpu_to_le32 ( MYSON_TX_CTRL_IC | MYSON_TX_CTRL_LD |
+                                   MYSON_TX_CTRL_FD | MYSON_TX_CTRL_CRC |
+                                   MYSON_TX_CTRL_PAD | MYSON_TX_CTRL_RTLC |
+                                   MYSON_TX_CTRL_PKTS ( iob_len ( iobuf ) ) |
+                                   MYSON_TX_CTRL_TBS ( iob_len ( iobuf ) ) );
+       wmb();
+       tx->status = cpu_to_le32 ( MYSON_TX_STAT_OWN );
+       wmb();
+
+       /* Notify card that there are packets ready to transmit */
+       writel ( 0, myson->regs + MYSON_TXPDR );
+
+       DBGC2 ( myson, "MYSON %p TX %d is [%llx,%llx)\n", myson, tx_idx,
+               ( ( unsigned long long ) address ),
+               ( ( unsigned long long ) address + iob_len ( iobuf ) ) );
+
+       return 0;
+}
+
+/**
+ * Poll for completed packets
+ *
+ * @v netdev           Network device
+ */
+static void myson_poll_tx ( struct net_device *netdev ) {
+       struct myson_nic *myson = netdev->priv;
+       struct myson_descriptor *tx;
+       unsigned int tx_idx;
+
+       /* Check for completed packets */
+       while ( myson->tx.cons != myson->tx.prod ) {
+
+               /* Get next transmit descriptor */
+               tx_idx = ( myson->tx.cons % MYSON_NUM_TX_DESC );
+               tx = &myson->tx.desc[tx_idx];
+
+               /* Stop if descriptor is still in use */
+               if ( tx->status & cpu_to_le32 ( MYSON_TX_STAT_OWN ) )
+                       return;
+
+               /* Complete TX descriptor */
+               if ( tx->status & cpu_to_le32 ( MYSON_TX_STAT_ABORT |
+                                               MYSON_TX_STAT_CSL ) ) {
+                       DBGC ( myson, "MYSON %p TX %d completion error "
+                              "(%08x)\n", myson, tx_idx,
+                              le32_to_cpu ( tx->status ) );
+                       netdev_tx_complete_next_err ( netdev, -EIO );
+               } else {
+                       DBGC2 ( myson, "MYSON %p TX %d complete\n",
+                               myson, tx_idx );
+                       netdev_tx_complete_next ( netdev );
+               }
+               myson->tx.cons++;
+       }
+}
+
+/**
+ * Poll for received packets
+ *
+ * @v netdev           Network device
+ */
+static void myson_poll_rx ( struct net_device *netdev ) {
+       struct myson_nic *myson = netdev->priv;
+       struct myson_descriptor *rx;
+       struct io_buffer *iobuf;
+       unsigned int rx_idx;
+       size_t len;
+
+       /* Check for received packets */
+       while ( myson->rx.cons != myson->rx.prod ) {
+
+               /* Get next receive descriptor */
+               rx_idx = ( myson->rx.cons % MYSON_NUM_RX_DESC );
+               rx = &myson->rx.desc[rx_idx];
+
+               /* Stop if descriptor is still in use */
+               if ( rx->status & MYSON_RX_STAT_OWN )
+                       return;
+
+               /* Populate I/O buffer */
+               iobuf = myson->rx_iobuf[rx_idx];
+               myson->rx_iobuf[rx_idx] = NULL;
+               len = MYSON_RX_STAT_FLNG ( le32_to_cpu ( rx->status ) );
+               iob_put ( iobuf, len - 4 /* strip CRC */ );
+
+               /* Hand off to network stack */
+               if ( rx->status & cpu_to_le32 ( MYSON_RX_STAT_ES ) ) {
+                       DBGC ( myson, "MYSON %p RX %d error (length %zd, "
+                              "status %08x)\n", myson, rx_idx, len,
+                              le32_to_cpu ( rx->status ) );
+                       netdev_rx_err ( netdev, iobuf, -EIO );
+               } else {
+                       DBGC2 ( myson, "MYSON %p RX %d complete (length "
+                               "%zd)\n", myson, rx_idx, len );
+                       netdev_rx ( netdev, iobuf );
+               }
+               myson->rx.cons++;
+       }
+}
+
+/**
+ * Poll for completed and received packets
+ *
+ * @v netdev           Network device
+ */
+static void myson_poll ( struct net_device *netdev ) {
+       struct myson_nic *myson = netdev->priv;
+       uint32_t isr;
+       unsigned int i;
+
+       /* Polling the ISR seems to really upset this card; it ends up
+        * getting no useful PCI transfers done and, for some reason,
+        * flooding the network with invalid packets.  Work around
+        * this by introducing deliberate delays between ISR reads.
+        */
+       for ( i = 0 ; i < MYSON_ISR_IODELAY_COUNT ; i++ )
+               iodelay();
+
+       /* Check for and acknowledge interrupts */
+       isr = readl ( myson->regs + MYSON_ISR );
+       if ( ! isr )
+               return;
+       writel ( isr, myson->regs + MYSON_ISR );
+
+       /* Poll for TX completions, if applicable */
+       if ( isr & MYSON_IRQ_TI )
+               myson_poll_tx ( netdev );
+
+       /* Poll for RX completionsm, if applicable */
+       if ( isr & MYSON_IRQ_RI )
+               myson_poll_rx ( netdev );
+
+       /* Refill RX ring */
+       myson_refill_rx ( netdev );
+}
+
+/**
+ * Enable or disable interrupts
+ *
+ * @v netdev           Network device
+ * @v enable           Interrupts should be enabled
+ */
+static void myson_irq ( struct net_device *netdev, int enable ) {
+       struct myson_nic *myson = netdev->priv;
+       uint32_t imr;
+
+       imr = ( enable ? ( MYSON_IRQ_TI | MYSON_IRQ_RI ) : 0 );
+       writel ( imr, myson->regs + MYSON_IMR );
+}
+
+/** Myson network device operations */
+static struct net_device_operations myson_operations = {
+       .open           = myson_open,
+       .close          = myson_close,
+       .transmit       = myson_transmit,
+       .poll           = myson_poll,
+       .irq            = myson_irq,
+};
+
+/******************************************************************************
+ *
+ * PCI interface
+ *
+ ******************************************************************************
+ */
+
+/**
+ * Probe PCI device
+ *
+ * @v pci              PCI device
+ * @ret rc             Return status code
+ */
+static int myson_probe ( struct pci_device *pci ) {
+       struct net_device *netdev;
+       struct myson_nic *myson;
+       union myson_physical_address mac;
+       int rc;
+
+       /* Allocate and initialise net device */
+       netdev = alloc_etherdev ( sizeof ( *myson ) );
+       if ( ! netdev ) {
+               rc = -ENOMEM;
+               goto err_alloc;
+       }
+       netdev_init ( netdev, &myson_operations );
+       myson = netdev->priv;
+       pci_set_drvdata ( pci, netdev );
+       netdev->dev = &pci->dev;
+       memset ( myson, 0, sizeof ( *myson ) );
+       myson_init_ring ( &myson->tx, MYSON_NUM_TX_DESC, MYSON_TXLBA );
+       myson_init_ring ( &myson->rx, MYSON_NUM_RX_DESC, MYSON_RXLBA );
+
+       /* Fix up PCI device */
+       adjust_pci_device ( pci );
+
+       /* Map registers */
+       myson->regs = ioremap ( pci->membase, MYSON_BAR_SIZE );
+
+       /* Reset the NIC */
+       if ( ( rc = myson_reset ( myson ) ) != 0 )
+               goto err_reset;
+
+       /* Read MAC address */
+       mac.reg.low = cpu_to_le32 ( readl ( myson->regs + MYSON_PAR0 ) );
+       mac.reg.high = cpu_to_le32 ( readl ( myson->regs + MYSON_PAR4 ) );
+       memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN );
+
+       /* Register network device */
+       if ( ( rc = register_netdev ( netdev ) ) != 0 )
+               goto err_register_netdev;
+
+       /* Mark as link up; we don't yet handle link state */
+       netdev_link_up ( netdev );
+
+       return 0;
+
+       unregister_netdev ( netdev );
+ err_register_netdev:
+       myson_reset ( myson );
+ err_reset:
+       netdev_nullify ( netdev );
+       netdev_put ( netdev );
+ err_alloc:
+       return rc;
+}
+
+/**
+ * Remove PCI device
+ *
+ * @v pci              PCI device
+ */
+static void myson_remove ( struct pci_device *pci ) {
+       struct net_device *netdev = pci_get_drvdata ( pci );
+       struct myson_nic *myson = netdev->priv;
+
+       /* Unregister network device */
+       unregister_netdev ( netdev );
+
+       /* Reset card */
+       myson_reset ( myson );
+
+       /* Free network device */
+       netdev_nullify ( netdev );
+       netdev_put ( netdev );
+}
+
+/** Myson PCI device IDs */
+static struct pci_device_id myson_nics[] = {
+        PCI_ROM ( 0x1516, 0x0800, "mtd800", "MTD-8xx", 0 ),
+        PCI_ROM ( 0x1516, 0x0803, "mtd803", "Surecom EP-320X-S", 0 ),
+        PCI_ROM ( 0x1516, 0x0891, "mtd891", "MTD-8xx", 0 ),
+};
+
+/** Myson PCI driver */
+struct pci_driver myson_driver __pci_driver = {
+       .ids = myson_nics,
+       .id_count = ( sizeof ( myson_nics ) / sizeof ( myson_nics[0] ) ),
+       .probe = myson_probe,
+       .remove = myson_remove,
+};
diff --git a/src/drivers/net/myson.h b/src/drivers/net/myson.h
new file mode 100644 (file)
index 0000000..8d7cc58
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef _MYSON_H
+#define _MYSON_H
+
+/** @file
+ *
+ * Myson Technology network card driver
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <ipxe/if_ether.h>
+
+/** BAR size */
+#define MYSON_BAR_SIZE 256
+
+/** A packet descriptor */
+struct myson_descriptor {
+       /** Status */
+       uint32_t status;
+       /** Control */
+       uint32_t control;
+       /** Buffer start address */
+       uint32_t address;
+       /** Next descriptor address */
+       uint32_t next;
+} __attribute__ (( packed ));
+
+/* Transmit status */
+#define MYSON_TX_STAT_OWN      0x80000000UL    /**< Owner */
+#define MYSON_TX_STAT_ABORT    0x00002000UL    /**< Abort */
+#define MYSON_TX_STAT_CSL      0x00001000UL    /**< Carrier sense lost */
+
+/* Transmit control */
+#define MYSON_TX_CTRL_IC       0x80000000UL    /**< Interrupt control */
+#define MYSON_TX_CTRL_LD       0x20000000UL    /**< Last descriptor */
+#define MYSON_TX_CTRL_FD       0x10000000UL    /**< First descriptor */
+#define MYSON_TX_CTRL_CRC      0x08000000UL    /**< CRC append */
+#define MYSON_TX_CTRL_PAD      0x04000000UL    /**< Pad control */
+#define MYSON_TX_CTRL_RTLC     0x02000000UL    /**< Retry late collision */
+#define MYSON_TX_CTRL_PKTS(x)  ( (x) << 11 )   /**< Packet size */
+#define MYSON_TX_CTRL_TBS(x)   ( (x) << 0 )    /**< Transmit buffer size */
+
+/* Receive status */
+#define MYSON_RX_STAT_OWN      0x80000000UL    /**< Owner */
+#define MYSON_RX_STAT_FLNG(status) ( ( (status) >> 16 ) & 0xfff )
+#define MYSON_RX_STAT_ES       0x00000080UL    /**< Error summary */
+
+/* Receive control */
+#define MYSON_RX_CTRL_RBS(x)   ( (x) << 0 )    /**< Receive buffer size */
+
+/** Descriptor ring alignment */
+#define MYSON_RING_ALIGN 4
+
+/** Physical Address Register 0 */
+#define MYSON_PAR0 0x00
+
+/** Physical Address Register 4 */
+#define MYSON_PAR4 0x04
+
+/** Physical address */
+union myson_physical_address {
+       struct {
+               uint32_t low;
+               uint32_t high;
+       } __attribute__ (( packed )) reg;
+       uint8_t raw[ETH_ALEN];
+};
+
+/** Transmit and Receive Configuration Register */
+#define MYSON_TCR_RCR 0x18
+#define MYSON_TCR_TXS          0x80000000UL    /**< Transmit status */
+#define MYSON_TCR_TE           0x00040000UL    /**< Transmit enable */
+#define MYSON_RCR_RXS          0x00008000UL    /**< Receive status */
+#define MYSON_RCR_PROM         0x00000080UL    /**< Promiscuous mode */
+#define MYSON_RCR_AB           0x00000040UL    /**< Accept broadcast */
+#define MYSON_RCR_AM           0x00000020UL    /**< Accept multicast */
+#define MYSON_RCR_ARP          0x00000008UL    /**< Accept runt packet */
+#define MYSON_RCR_ALP          0x00000004UL    /**< Accept long packet */
+#define MYSON_RCR_RE           0x00000001UL    /**< Receive enable */
+
+/** Maximum time to wait for transmit and receive to be idle, in milliseconds */
+#define MYSON_IDLE_MAX_WAIT_MS 100
+
+/** Bus Command Register */
+#define MYSON_BCR 0x1c
+#define MYSON_BCR_RLE          0x00000100UL    /**< Read line enable */
+#define MYSON_BCR_RME          0x00000080UL    /**< Read multiple enable */
+#define MYSON_BCR_WIE          0x00000040UL    /**< Write and invalidate */
+#define MYSON_BCR_PBL(x)       ( (x) << 3 )    /**< Burst length */
+#define MYSON_BCR_PBL_MASK     MYSON_BCR_PBL ( 0x7 )
+#define MYSON_BCR_PBL_DEFAULT  MYSON_BCR_PBL ( 0x6 )
+#define MYSON_BCR_SWR          0x00000001UL    /**< Software reset */
+
+/** Maximum time to wait for a reset, in milliseconds */
+#define MYSON_RESET_MAX_WAIT_MS 100
+
+/** Transmit Poll Demand Register */
+#define MYSON_TXPDR 0x20
+
+/** Receive Poll Demand Register */
+#define MYSON_RXPDR 0x24
+
+/** Transmit List Base Address */
+#define MYSON_TXLBA 0x2c
+
+/** Number of transmit descriptors */
+#define MYSON_NUM_TX_DESC 4
+
+/** Receive List Base Address */
+#define MYSON_RXLBA 0x30
+
+/** Number of receive descriptors */
+#define MYSON_NUM_RX_DESC 4
+
+/** Receive buffer length */
+#define MYSON_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ )
+
+/** Interrupt Status Register */
+#define MYSON_ISR 0x34
+#define MYSON_IRQ_TI           0x00000008UL    /**< Transmit interrupt */
+#define MYSON_IRQ_RI           0x00000004UL    /**< Receive interrupt */
+
+/** Number of I/O delays between ISR reads */
+#define MYSON_ISR_IODELAY_COUNT 4
+
+/** Interrupt Mask Register */
+#define MYSON_IMR 0x38
+
+/** Boot ROM / EEPROM / MII Management Register */
+#define MYSON_ROM_MII 0x40
+#define MYSON_ROM_AUTOLD       0x00100000UL    /**< Auto load */
+
+/** Maximum time to wait for a configuration reload, in milliseconds */
+#define MYSON_AUTOLD_MAX_WAIT_MS 100
+
+/** A Myson descriptor ring */
+struct myson_ring {
+       /** Descriptors */
+       struct myson_descriptor *desc;
+       /** Producer index */
+       unsigned int prod;
+       /** Consumer index */
+       unsigned int cons;
+
+       /** Number of descriptors */
+       unsigned int count;
+       /** Descriptor start address register */
+       unsigned int reg;
+};
+
+/**
+ * Initialise descriptor ring
+ *
+ * @v ring             Descriptor ring
+ * @v count            Number of descriptors
+ * @v reg              Descriptor base address register
+ */
+static inline __attribute__ (( always_inline)) void
+myson_init_ring ( struct myson_ring *ring, unsigned int count,
+                 unsigned int reg ) {
+       ring->count = count;
+       ring->reg = reg;
+}
+
+/** A myson network card */
+struct myson_nic {
+       /** Registers */
+       void *regs;
+
+       /** Transmit descriptor ring */
+       struct myson_ring tx;
+       /** Receive descriptor ring */
+       struct myson_ring rx;
+       /** Receive I/O buffers */
+       struct io_buffer *rx_iobuf[MYSON_NUM_RX_DESC];
+};
+
+/**
+ * Check if card can access physical address
+ *
+ * @v address          Physical address
+ * @v address_ok       Card can access physical address
+ */
+static inline __attribute__ (( always_inline )) int
+myson_address_ok ( physaddr_t address ) {
+
+       /* In a 32-bit build, all addresses can be accessed */
+       if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
+               return 1;
+
+       /* Card can access all addresses below 4GB */
+       if ( ( address & ~0xffffffffULL ) == 0 )
+               return 1;
+
+       return 0;
+}
+
+#endif /* _MYSON_H */
index 471ba77c91b3418f28729df782dc53487eaacbf9..7de833d08cc19a36482d0ba06b92704fee651102 100644 (file)
@@ -145,6 +145,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_realtek                     ( ERRFILE_DRIVER | 0x00630000 )
 #define ERRFILE_skeleton            ( ERRFILE_DRIVER | 0x00640000 )
 #define ERRFILE_intel               ( ERRFILE_DRIVER | 0x00650000 )
+#define ERRFILE_myson               ( ERRFILE_DRIVER | 0x00660000 )
 
 #define ERRFILE_scsi                ( ERRFILE_DRIVER | 0x00700000 )
 #define ERRFILE_arbel               ( ERRFILE_DRIVER | 0x00710000 )