Home | History | Annotate | Line # | Download | only in bfin
dv-bfin_emac.c revision 1.1.1.6
      1      1.1  christos /* Blackfin Ethernet Media Access Controller (EMAC) model.
      2      1.1  christos 
      3  1.1.1.6  christos    Copyright (C) 2010-2020 Free Software Foundation, Inc.
      4      1.1  christos    Contributed by Analog Devices, Inc.
      5      1.1  christos 
      6      1.1  christos    This file is part of simulators.
      7      1.1  christos 
      8      1.1  christos    This program is free software; you can redistribute it and/or modify
      9      1.1  christos    it under the terms of the GNU General Public License as published by
     10      1.1  christos    the Free Software Foundation; either version 3 of the License, or
     11      1.1  christos    (at your option) any later version.
     12      1.1  christos 
     13      1.1  christos    This program is distributed in the hope that it will be useful,
     14      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     15      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16      1.1  christos    GNU General Public License for more details.
     17      1.1  christos 
     18      1.1  christos    You should have received a copy of the GNU General Public License
     19      1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     20      1.1  christos 
     21      1.1  christos #include "config.h"
     22      1.1  christos 
     23      1.1  christos #include <errno.h>
     24      1.1  christos #include <fcntl.h>
     25      1.1  christos #include <unistd.h>
     26      1.1  christos 
     27      1.1  christos #ifdef HAVE_SYS_IOCTL_H
     28      1.1  christos #include <sys/ioctl.h>
     29      1.1  christos #endif
     30      1.1  christos #ifdef HAVE_NET_IF_H
     31      1.1  christos #include <net/if.h>
     32      1.1  christos #endif
     33      1.1  christos #ifdef HAVE_LINUX_IF_TUN_H
     34      1.1  christos #include <linux/if_tun.h>
     35      1.1  christos #endif
     36      1.1  christos 
     37      1.1  christos #ifdef HAVE_LINUX_IF_TUN_H
     38      1.1  christos # define WITH_TUN 1
     39      1.1  christos #else
     40      1.1  christos # define WITH_TUN 0
     41      1.1  christos #endif
     42      1.1  christos 
     43      1.1  christos #include "sim-main.h"
     44      1.1  christos #include "sim-hw.h"
     45      1.1  christos #include "devices.h"
     46      1.1  christos #include "dv-bfin_emac.h"
     47      1.1  christos 
     48      1.1  christos /* XXX: This doesn't support partial DMA transfers.  */
     49      1.1  christos /* XXX: The TUN pieces should be pushed to the PHY so that we work with
     50      1.1  christos         multiple "networks" and the PHY takes care of it.  */
     51      1.1  christos 
     52      1.1  christos struct bfin_emac
     53      1.1  christos {
     54      1.1  christos   /* This top portion matches common dv_bfin struct.  */
     55      1.1  christos   bu32 base;
     56      1.1  christos   struct hw *dma_master;
     57      1.1  christos   bool acked;
     58      1.1  christos 
     59      1.1  christos   int tap;
     60      1.1  christos #if WITH_TUN
     61      1.1  christos   struct ifreq ifr;
     62      1.1  christos #endif
     63      1.1  christos   bu32 rx_crc;
     64      1.1  christos 
     65      1.1  christos   /* Order after here is important -- matches hardware MMR layout.  */
     66      1.1  christos   bu32 opmode, addrlo, addrhi, hashlo, hashhi, staadd, stadat, flc, vlan1, vlan2;
     67      1.1  christos   bu32 _pad0;
     68      1.1  christos   bu32 wkup_ctl, wkup_ffmsk0, wkup_ffmsk1, wkup_ffmsk2, wkup_ffmsk3;
     69      1.1  christos   bu32 wkup_ffcmd, wkup_ffoff, wkup_ffcrc0, wkup_ffcrc1;
     70      1.1  christos   bu32 _pad1[4];
     71      1.1  christos   bu32 sysctl, systat, rx_stat, rx_stky, rx_irqe, tx_stat, tx_stky, tx_irqe;
     72      1.1  christos   bu32 mmc_ctl, mmc_rirqs, mmc_rirqe, mmc_tirqs, mmc_tirqe;
     73      1.1  christos   bu32 _pad2[3];
     74      1.1  christos   bu16 BFIN_MMR_16(ptp_ctl);
     75      1.1  christos   bu16 BFIN_MMR_16(ptp_ie);
     76      1.1  christos   bu16 BFIN_MMR_16(ptp_istat);
     77      1.1  christos   bu32 ptp_foff, ptp_fv1, ptp_fv2, ptp_fv3, ptp_addend, ptp_accr, ptp_offset;
     78      1.1  christos   bu32 ptp_timelo, ptp_timehi, ptp_rxsnaplo, ptp_rxsnaphi, ptp_txsnaplo;
     79      1.1  christos   bu32 ptp_txsnaphi, ptp_alarmlo, ptp_alarmhi, ptp_id_off, ptp_id_snap;
     80      1.1  christos   bu32 ptp_pps_startlo, ptp_pps_starthi, ptp_pps_period;
     81      1.1  christos   bu32 _pad3[1];
     82      1.1  christos   bu32 rxc_ok, rxc_fcs, rxc_lign, rxc_octet, rxc_dmaovf, rxc_unicst, rxc_multi;
     83      1.1  christos   bu32 rxc_broad, rxc_lnerri, rxc_lnerro, rxc_long, rxc_macctl, rxc_opcode;
     84      1.1  christos   bu32 rxc_pause, rxc_allfrm, rxc_alloct, rxc_typed, rxc_short, rxc_eq64;
     85      1.1  christos   bu32 rxc_lt128, rxc_lt256, rxc_lt512, rxc_lt1024, rxc_ge1024;
     86      1.1  christos   bu32 _pad4[8];
     87      1.1  christos   bu32 txc_ok, txc_1col, txc_gt1col, txc_octet, txc_defer, txc_latecl;
     88      1.1  christos   bu32 txc_xs_col, txc_dmaund, txc_crserr, txc_unicst, txc_multi, txc_broad;
     89      1.1  christos   bu32 txc_xs_dfr, txc_macctl, txc_allfrm, txc_alloct, txc_eq64, txc_lt128;
     90      1.1  christos   bu32 txc_lt256, txc_lt512, txc_lt1024, txc_ge1024, txc_abort;
     91      1.1  christos };
     92      1.1  christos #define mmr_base()      offsetof(struct bfin_emac, opmode)
     93      1.1  christos #define mmr_offset(mmr) (offsetof(struct bfin_emac, mmr) - mmr_base())
     94      1.1  christos #define mmr_idx(mmr)    (mmr_offset (mmr) / 4)
     95      1.1  christos 
     96      1.1  christos static const char * const mmr_names[BFIN_MMR_EMAC_SIZE / 4] =
     97      1.1  christos {
     98      1.1  christos   "EMAC_OPMODE", "EMAC_ADDRLO", "EMAC_ADDRHI", "EMAC_HASHLO", "EMAC_HASHHI",
     99      1.1  christos   "EMAC_STAADD", "EMAC_STADAT", "EMAC_FLC", "EMAC_VLAN1", "EMAC_VLAN2", NULL,
    100      1.1  christos   "EMAC_WKUP_CTL", "EMAC_WKUP_FFMSK0", "EMAC_WKUP_FFMSK1", "EMAC_WKUP_FFMSK2",
    101      1.1  christos   "EMAC_WKUP_FFMSK3", "EMAC_WKUP_FFCMD", "EMAC_WKUP_FFOFF", "EMAC_WKUP_FFCRC0",
    102      1.1  christos   "EMAC_WKUP_FFCRC1", [mmr_idx (sysctl)] = "EMAC_SYSCTL", "EMAC_SYSTAT",
    103      1.1  christos   "EMAC_RX_STAT", "EMAC_RX_STKY", "EMAC_RX_IRQE", "EMAC_TX_STAT",
    104      1.1  christos   "EMAC_TX_STKY", "EMAC_TX_IRQE", "EMAC_MMC_CTL", "EMAC_MMC_RIRQS",
    105      1.1  christos   "EMAC_MMC_RIRQE", "EMAC_MMC_TIRQS", "EMAC_MMC_TIRQE",
    106      1.1  christos   [mmr_idx (ptp_ctl)] = "EMAC_PTP_CTL", "EMAC_PTP_IE", "EMAC_PTP_ISTAT",
    107      1.1  christos   "EMAC_PTP_FOFF", "EMAC_PTP_FV1", "EMAC_PTP_FV2", "EMAC_PTP_FV3",
    108      1.1  christos   "EMAC_PTP_ADDEND", "EMAC_PTP_ACCR", "EMAC_PTP_OFFSET", "EMAC_PTP_TIMELO",
    109      1.1  christos   "EMAC_PTP_TIMEHI", "EMAC_PTP_RXSNAPLO", "EMAC_PTP_RXSNAPHI",
    110      1.1  christos   "EMAC_PTP_TXSNAPLO", "EMAC_PTP_TXSNAPHI", "EMAC_PTP_ALARMLO",
    111      1.1  christos   "EMAC_PTP_ALARMHI", "EMAC_PTP_ID_OFF", "EMAC_PTP_ID_SNAP",
    112      1.1  christos   "EMAC_PTP_PPS_STARTLO", "EMAC_PTP_PPS_STARTHI", "EMAC_PTP_PPS_PERIOD",
    113      1.1  christos   [mmr_idx (rxc_ok)] = "EMAC_RXC_OK", "EMAC_RXC_FCS", "EMAC_RXC_LIGN",
    114      1.1  christos   "EMAC_RXC_OCTET", "EMAC_RXC_DMAOVF", "EMAC_RXC_UNICST", "EMAC_RXC_MULTI",
    115      1.1  christos   "EMAC_RXC_BROAD", "EMAC_RXC_LNERRI", "EMAC_RXC_LNERRO", "EMAC_RXC_LONG",
    116      1.1  christos   "EMAC_RXC_MACCTL", "EMAC_RXC_OPCODE", "EMAC_RXC_PAUSE", "EMAC_RXC_ALLFRM",
    117      1.1  christos   "EMAC_RXC_ALLOCT", "EMAC_RXC_TYPED", "EMAC_RXC_SHORT", "EMAC_RXC_EQ64",
    118      1.1  christos   "EMAC_RXC_LT128", "EMAC_RXC_LT256", "EMAC_RXC_LT512", "EMAC_RXC_LT1024",
    119      1.1  christos   "EMAC_RXC_GE1024",
    120      1.1  christos   [mmr_idx (txc_ok)] = "EMAC_TXC_OK", "EMAC_TXC_1COL", "EMAC_TXC_GT1COL",
    121      1.1  christos   "EMAC_TXC_OCTET", "EMAC_TXC_DEFER", "EMAC_TXC_LATECL", "EMAC_TXC_XS_COL",
    122      1.1  christos   "EMAC_TXC_DMAUND", "EMAC_TXC_CRSERR", "EMAC_TXC_UNICST", "EMAC_TXC_MULTI",
    123      1.1  christos   "EMAC_TXC_BROAD", "EMAC_TXC_XS_DFR", "EMAC_TXC_MACCTL", "EMAC_TXC_ALLFRM",
    124      1.1  christos   "EMAC_TXC_ALLOCT", "EMAC_TXC_EQ64", "EMAC_TXC_LT128", "EMAC_TXC_LT256",
    125      1.1  christos   "EMAC_TXC_LT512", "EMAC_TXC_LT1024", "EMAC_TXC_GE1024", "EMAC_TXC_ABORT",
    126      1.1  christos };
    127      1.1  christos #define mmr_name(off) (mmr_names[(off) / 4] ? : "<INV>")
    128      1.1  christos 
    129      1.1  christos static struct hw *
    130      1.1  christos mii_find_phy (struct hw *me, bu8 addr)
    131      1.1  christos {
    132      1.1  christos   struct hw *phy = hw_child (me);
    133      1.1  christos   while (phy && --addr)
    134      1.1  christos     phy = hw_sibling (phy);
    135      1.1  christos   return phy;
    136      1.1  christos }
    137      1.1  christos 
    138      1.1  christos static void
    139      1.1  christos mii_write (struct hw *me)
    140      1.1  christos {
    141      1.1  christos   SIM_DESC sd = hw_system (me);
    142      1.1  christos   struct bfin_emac *emac = hw_data (me);
    143      1.1  christos   struct hw *phy;
    144      1.1  christos   bu8 addr = PHYAD (emac->staadd);
    145      1.1  christos   bu8 reg = REGAD (emac->staadd);
    146      1.1  christos   bu16 data = emac->stadat;
    147      1.1  christos 
    148      1.1  christos   phy = mii_find_phy (me, addr);
    149      1.1  christos   if (!phy)
    150      1.1  christos     return;
    151      1.1  christos   sim_hw_io_write_buffer (sd, phy, &data, 1, reg, 2);
    152      1.1  christos }
    153      1.1  christos 
    154      1.1  christos static void
    155      1.1  christos mii_read (struct hw *me)
    156      1.1  christos {
    157      1.1  christos   SIM_DESC sd = hw_system (me);
    158      1.1  christos   struct bfin_emac *emac = hw_data (me);
    159      1.1  christos   struct hw *phy;
    160      1.1  christos   bu8 addr = PHYAD (emac->staadd);
    161      1.1  christos   bu8 reg = REGAD (emac->staadd);
    162      1.1  christos   bu16 data;
    163      1.1  christos 
    164      1.1  christos   phy = mii_find_phy (me, addr);
    165      1.1  christos   if (!phy || sim_hw_io_read_buffer (sd, phy, &data, 1, reg, 2) != 2)
    166      1.1  christos     data = 0xffff;
    167      1.1  christos 
    168      1.1  christos   emac->stadat = data;
    169      1.1  christos }
    170      1.1  christos 
    171      1.1  christos static unsigned
    172      1.1  christos bfin_emac_io_write_buffer (struct hw *me, const void *source,
    173      1.1  christos 			   int space, address_word addr, unsigned nr_bytes)
    174      1.1  christos {
    175      1.1  christos   struct bfin_emac *emac = hw_data (me);
    176      1.1  christos   bu32 mmr_off;
    177      1.1  christos   bu32 value;
    178      1.1  christos   bu32 *valuep;
    179      1.1  christos 
    180  1.1.1.3  christos   /* Invalid access mode is higher priority than missing register.  */
    181      1.1  christos   /* XXX: 16bit accesses are allowed ...  */
    182  1.1.1.3  christos   if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, true))
    183  1.1.1.3  christos     return 0;
    184      1.1  christos   value = dv_load_4 (source);
    185      1.1  christos 
    186      1.1  christos   mmr_off = addr - emac->base;
    187      1.1  christos   valuep = (void *)((unsigned long)emac + mmr_base() + mmr_off);
    188      1.1  christos 
    189      1.1  christos   HW_TRACE_WRITE ();
    190      1.1  christos 
    191      1.1  christos   switch (mmr_off)
    192      1.1  christos     {
    193      1.1  christos     case mmr_offset(hashlo):
    194      1.1  christos     case mmr_offset(hashhi):
    195      1.1  christos     case mmr_offset(stadat):
    196      1.1  christos     case mmr_offset(flc):
    197      1.1  christos     case mmr_offset(vlan1):
    198      1.1  christos     case mmr_offset(vlan2):
    199      1.1  christos     case mmr_offset(wkup_ffmsk0):
    200      1.1  christos     case mmr_offset(wkup_ffmsk1):
    201      1.1  christos     case mmr_offset(wkup_ffmsk2):
    202      1.1  christos     case mmr_offset(wkup_ffmsk3):
    203      1.1  christos     case mmr_offset(wkup_ffcmd):
    204      1.1  christos     case mmr_offset(wkup_ffoff):
    205      1.1  christos     case mmr_offset(wkup_ffcrc0):
    206      1.1  christos     case mmr_offset(wkup_ffcrc1):
    207      1.1  christos     case mmr_offset(sysctl):
    208      1.1  christos     case mmr_offset(rx_irqe):
    209      1.1  christos     case mmr_offset(tx_irqe):
    210      1.1  christos     case mmr_offset(mmc_rirqe):
    211      1.1  christos     case mmr_offset(mmc_tirqe):
    212      1.1  christos       *valuep = value;
    213      1.1  christos       break;
    214      1.1  christos     case mmr_offset(opmode):
    215      1.1  christos       if (!(*valuep & RE) && (value & RE))
    216      1.1  christos 	emac->rx_stat &= ~RX_COMP;
    217      1.1  christos       if (!(*valuep & TE) && (value & TE))
    218      1.1  christos 	emac->tx_stat &= ~TX_COMP;
    219      1.1  christos       *valuep = value;
    220      1.1  christos       break;
    221      1.1  christos     case mmr_offset(addrlo):
    222      1.1  christos     case mmr_offset(addrhi):
    223      1.1  christos       *valuep = value;
    224      1.1  christos       break;
    225      1.1  christos     case mmr_offset(wkup_ctl):
    226      1.1  christos       dv_w1c_4_partial (valuep, value, 0xf20);
    227      1.1  christos       break;
    228      1.1  christos     case mmr_offset(systat):
    229      1.1  christos       dv_w1c_4 (valuep, value, 0xe1);
    230      1.1  christos       break;
    231      1.1  christos     case mmr_offset(staadd):
    232      1.1  christos       *valuep = value | STABUSY;
    233      1.1  christos       if (value & STAOP)
    234      1.1  christos 	mii_write (me);
    235      1.1  christos       else
    236      1.1  christos 	mii_read (me);
    237      1.1  christos       *valuep &= ~STABUSY;
    238      1.1  christos       break;
    239      1.1  christos     case mmr_offset(rx_stat):
    240      1.1  christos     case mmr_offset(tx_stat):
    241      1.1  christos       /* Discard writes to these.  */
    242      1.1  christos       break;
    243      1.1  christos     case mmr_offset(rx_stky):
    244      1.1  christos     case mmr_offset(tx_stky):
    245      1.1  christos     case mmr_offset(mmc_rirqs):
    246      1.1  christos     case mmr_offset(mmc_tirqs):
    247      1.1  christos       dv_w1c_4 (valuep, value, -1);
    248      1.1  christos       break;
    249      1.1  christos     case mmr_offset(mmc_ctl):
    250      1.1  christos       /* Writing to bit 0 clears all counters.  */
    251      1.1  christos       *valuep = value & ~1;
    252      1.1  christos       if (value & 1)
    253      1.1  christos 	{
    254      1.1  christos 	  memset (&emac->rxc_ok, 0, mmr_offset (rxc_ge1024) - mmr_offset (rxc_ok) + 4);
    255      1.1  christos 	  memset (&emac->txc_ok, 0, mmr_offset (txc_abort) - mmr_offset (txc_ok) + 4);
    256      1.1  christos 	}
    257      1.1  christos       break;
    258      1.1  christos     case mmr_offset(rxc_ok) ... mmr_offset(rxc_ge1024):
    259      1.1  christos     case mmr_offset(txc_ok) ... mmr_offset(txc_abort):
    260      1.1  christos       /* XXX: Are these supposed to be read-only ?  */
    261      1.1  christos       *valuep = value;
    262      1.1  christos       break;
    263      1.1  christos     case mmr_offset(ptp_ctl) ... mmr_offset(ptp_pps_period):
    264      1.1  christos       /* XXX: Only on some models; ignore for now.  */
    265      1.1  christos       break;
    266      1.1  christos     default:
    267      1.1  christos       dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
    268  1.1.1.3  christos       return 0;
    269      1.1  christos     }
    270      1.1  christos 
    271      1.1  christos   return nr_bytes;
    272      1.1  christos }
    273      1.1  christos 
    274      1.1  christos static unsigned
    275      1.1  christos bfin_emac_io_read_buffer (struct hw *me, void *dest,
    276      1.1  christos 			  int space, address_word addr, unsigned nr_bytes)
    277      1.1  christos {
    278      1.1  christos   struct bfin_emac *emac = hw_data (me);
    279      1.1  christos   bu32 mmr_off;
    280      1.1  christos   bu32 *valuep;
    281      1.1  christos 
    282  1.1.1.3  christos   /* Invalid access mode is higher priority than missing register.  */
    283      1.1  christos   /* XXX: 16bit accesses are allowed ...  */
    284  1.1.1.3  christos   if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, false))
    285  1.1.1.3  christos     return 0;
    286      1.1  christos 
    287      1.1  christos   mmr_off = addr - emac->base;
    288      1.1  christos   valuep = (void *)((unsigned long)emac + mmr_base() + mmr_off);
    289      1.1  christos 
    290      1.1  christos   HW_TRACE_READ ();
    291      1.1  christos 
    292      1.1  christos   switch (mmr_off)
    293      1.1  christos     {
    294      1.1  christos     case mmr_offset(opmode):
    295      1.1  christos     case mmr_offset(addrlo):
    296      1.1  christos     case mmr_offset(addrhi):
    297      1.1  christos     case mmr_offset(hashlo):
    298      1.1  christos     case mmr_offset(hashhi):
    299      1.1  christos     case mmr_offset(staadd):
    300      1.1  christos     case mmr_offset(stadat):
    301      1.1  christos     case mmr_offset(flc):
    302      1.1  christos     case mmr_offset(vlan1):
    303      1.1  christos     case mmr_offset(vlan2):
    304      1.1  christos     case mmr_offset(wkup_ctl):
    305      1.1  christos     case mmr_offset(wkup_ffmsk0):
    306      1.1  christos     case mmr_offset(wkup_ffmsk1):
    307      1.1  christos     case mmr_offset(wkup_ffmsk2):
    308      1.1  christos     case mmr_offset(wkup_ffmsk3):
    309      1.1  christos     case mmr_offset(wkup_ffcmd):
    310      1.1  christos     case mmr_offset(wkup_ffoff):
    311      1.1  christos     case mmr_offset(wkup_ffcrc0):
    312      1.1  christos     case mmr_offset(wkup_ffcrc1):
    313      1.1  christos     case mmr_offset(sysctl):
    314      1.1  christos     case mmr_offset(systat):
    315      1.1  christos     case mmr_offset(rx_stat):
    316      1.1  christos     case mmr_offset(rx_stky):
    317      1.1  christos     case mmr_offset(rx_irqe):
    318      1.1  christos     case mmr_offset(tx_stat):
    319      1.1  christos     case mmr_offset(tx_stky):
    320      1.1  christos     case mmr_offset(tx_irqe):
    321      1.1  christos     case mmr_offset(mmc_rirqs):
    322      1.1  christos     case mmr_offset(mmc_rirqe):
    323      1.1  christos     case mmr_offset(mmc_tirqs):
    324      1.1  christos     case mmr_offset(mmc_tirqe):
    325      1.1  christos     case mmr_offset(mmc_ctl):
    326      1.1  christos     case mmr_offset(rxc_ok) ... mmr_offset(rxc_ge1024):
    327      1.1  christos     case mmr_offset(txc_ok) ... mmr_offset(txc_abort):
    328      1.1  christos       dv_store_4 (dest, *valuep);
    329      1.1  christos       break;
    330      1.1  christos     case mmr_offset(ptp_ctl) ... mmr_offset(ptp_pps_period):
    331      1.1  christos       /* XXX: Only on some models; ignore for now.  */
    332      1.1  christos       break;
    333      1.1  christos     default:
    334      1.1  christos       dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
    335  1.1.1.3  christos       return 0;
    336      1.1  christos     }
    337      1.1  christos 
    338      1.1  christos   return nr_bytes;
    339      1.1  christos }
    340      1.1  christos 
    341      1.1  christos static void
    342      1.1  christos attach_bfin_emac_regs (struct hw *me, struct bfin_emac *emac)
    343      1.1  christos {
    344      1.1  christos   address_word attach_address;
    345      1.1  christos   int attach_space;
    346      1.1  christos   unsigned attach_size;
    347      1.1  christos   reg_property_spec reg;
    348      1.1  christos 
    349      1.1  christos   if (hw_find_property (me, "reg") == NULL)
    350      1.1  christos     hw_abort (me, "Missing \"reg\" property");
    351      1.1  christos 
    352      1.1  christos   if (!hw_find_reg_array_property (me, "reg", 0, &reg))
    353      1.1  christos     hw_abort (me, "\"reg\" property must contain three addr/size entries");
    354      1.1  christos 
    355      1.1  christos   hw_unit_address_to_attach_address (hw_parent (me),
    356      1.1  christos 				     &reg.address,
    357      1.1  christos 				     &attach_space, &attach_address, me);
    358      1.1  christos   hw_unit_size_to_attach_size (hw_parent (me), &reg.size, &attach_size, me);
    359      1.1  christos 
    360      1.1  christos   if (attach_size != BFIN_MMR_EMAC_SIZE)
    361      1.1  christos     hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_EMAC_SIZE);
    362      1.1  christos 
    363      1.1  christos   hw_attach_address (hw_parent (me),
    364      1.1  christos 		     0, attach_space, attach_address, attach_size, me);
    365      1.1  christos 
    366      1.1  christos   emac->base = attach_address;
    367      1.1  christos }
    368      1.1  christos 
    369      1.1  christos static struct dv_bfin *dma_tx;
    370      1.1  christos 
    371      1.1  christos static unsigned
    372      1.1  christos bfin_emac_dma_read_buffer (struct hw *me, void *dest, int space,
    373      1.1  christos 			   unsigned_word addr, unsigned nr_bytes)
    374      1.1  christos {
    375      1.1  christos   struct bfin_emac *emac = hw_data (me);
    376      1.1  christos   struct dv_bfin *dma = hw_data (emac->dma_master);
    377      1.1  christos   unsigned char *data = dest;
    378      1.1  christos   static bool flop; /* XXX: This sucks.  */
    379      1.1  christos   bu16 len;
    380      1.1  christos   ssize_t ret;
    381      1.1  christos 
    382      1.1  christos   HW_TRACE_DMA_READ ();
    383      1.1  christos 
    384      1.1  christos   if (dma_tx == dma)
    385      1.1  christos     {
    386      1.1  christos       /* Handle the TX turn around and write the status.  */
    387      1.1  christos       emac->tx_stat |= TX_OK;
    388      1.1  christos       emac->tx_stky |= TX_OK;
    389      1.1  christos 
    390      1.1  christos       memcpy (data, &emac->tx_stat, 4);
    391      1.1  christos 
    392      1.1  christos       dma->acked = true;
    393      1.1  christos       return 4;
    394      1.1  christos     }
    395      1.1  christos 
    396      1.1  christos   if (!(emac->opmode & RE))
    397      1.1  christos     return 0;
    398      1.1  christos 
    399      1.1  christos   if (!flop)
    400      1.1  christos     {
    401      1.1  christos       ssize_t pad_ret;
    402      1.1  christos       /* Outgoing DMA buffer has 16bit len prepended to it.  */
    403      1.1  christos       data += 2;
    404      1.1  christos 
    405      1.1  christos       /* This doesn't seem to work.
    406      1.1  christos       if (emac->sysctl & RXDWA)
    407      1.1  christos 	{
    408      1.1  christos 	  memset (data, 0, 2);
    409      1.1  christos 	  data += 2;
    410      1.1  christos 	} */
    411      1.1  christos 
    412      1.1  christos       ret = read (emac->tap, data, nr_bytes);
    413      1.1  christos       if (ret < 0)
    414      1.1  christos 	return 0;
    415      1.1  christos       ret += 4; /* include crc */
    416  1.1.1.3  christos       pad_ret = max (ret + 4, 64);
    417      1.1  christos       len = pad_ret;
    418      1.1  christos       memcpy (dest, &len, 2);
    419      1.1  christos 
    420      1.1  christos       pad_ret = (pad_ret + 3) & ~3;
    421      1.1  christos       if (ret < pad_ret)
    422      1.1  christos 	memset (data + ret, 0, pad_ret - ret);
    423      1.1  christos       pad_ret += 4;
    424      1.1  christos 
    425      1.1  christos       /* XXX: Need to check -- u-boot doesn't look at this.  */
    426      1.1  christos       if (emac->sysctl & RXCKS)
    427      1.1  christos 	{
    428      1.1  christos 	  pad_ret += 4;
    429      1.1  christos 	  emac->rx_crc = 0;
    430      1.1  christos 	}
    431      1.1  christos       ret = pad_ret;
    432      1.1  christos 
    433      1.1  christos       /* XXX: Don't support promiscuous yet.  */
    434      1.1  christos       emac->rx_stat |= RX_ACCEPT;
    435      1.1  christos       emac->rx_stat = (emac->rx_stat & ~RX_FRLEN) | len;
    436      1.1  christos 
    437      1.1  christos       emac->rx_stat |= RX_COMP;
    438      1.1  christos       emac->rx_stky |= RX_COMP;
    439      1.1  christos     }
    440      1.1  christos   else
    441      1.1  christos     {
    442      1.1  christos       /* Write the RX status and crc info.  */
    443      1.1  christos       emac->rx_stat |= RX_OK;
    444      1.1  christos       emac->rx_stky |= RX_OK;
    445      1.1  christos 
    446      1.1  christos       ret = 4;
    447      1.1  christos       if (emac->sysctl & RXCKS)
    448      1.1  christos 	{
    449      1.1  christos 	  memcpy (data, &emac->rx_crc, 4);
    450      1.1  christos 	  data += 4;
    451      1.1  christos 	  ret += 4;
    452      1.1  christos 	}
    453      1.1  christos       memcpy (data, &emac->rx_stat, 4);
    454      1.1  christos     }
    455      1.1  christos 
    456      1.1  christos   flop = !flop;
    457      1.1  christos   dma->acked = true;
    458      1.1  christos   return ret;
    459      1.1  christos }
    460      1.1  christos 
    461      1.1  christos static unsigned
    462      1.1  christos bfin_emac_dma_write_buffer (struct hw *me, const void *source,
    463      1.1  christos 			    int space, unsigned_word addr,
    464      1.1  christos 			    unsigned nr_bytes,
    465      1.1  christos 			    int violate_read_only_section)
    466      1.1  christos {
    467      1.1  christos   struct bfin_emac *emac = hw_data (me);
    468      1.1  christos   struct dv_bfin *dma = hw_data (emac->dma_master);
    469      1.1  christos   const unsigned char *data = source;
    470      1.1  christos   bu16 len;
    471      1.1  christos   ssize_t ret;
    472      1.1  christos 
    473      1.1  christos   HW_TRACE_DMA_WRITE ();
    474      1.1  christos 
    475      1.1  christos   if (!(emac->opmode & TE))
    476      1.1  christos     return 0;
    477      1.1  christos 
    478      1.1  christos   /* Incoming DMA buffer has 16bit len prepended to it.  */
    479      1.1  christos   memcpy (&len, data, 2);
    480      1.1  christos   if (!len)
    481      1.1  christos     return 0;
    482      1.1  christos 
    483      1.1  christos   ret = write (emac->tap, data + 2, len);
    484      1.1  christos   if (ret < 0)
    485      1.1  christos     return 0;
    486      1.1  christos   ret += 2;
    487      1.1  christos 
    488      1.1  christos   emac->tx_stat |= TX_COMP;
    489      1.1  christos   emac->tx_stky |= TX_COMP;
    490      1.1  christos 
    491      1.1  christos   dma_tx = dma;
    492      1.1  christos   dma->acked = true;
    493      1.1  christos   return ret;
    494      1.1  christos }
    495      1.1  christos 
    496      1.1  christos static const struct hw_port_descriptor bfin_emac_ports[] =
    497      1.1  christos {
    498      1.1  christos   { "tx",   DV_PORT_TX,   0, output_port, },
    499      1.1  christos   { "rx",   DV_PORT_RX,   0, output_port, },
    500      1.1  christos   { "stat", DV_PORT_STAT, 0, output_port, },
    501      1.1  christos   { NULL, 0, 0, 0, },
    502      1.1  christos };
    503      1.1  christos 
    504      1.1  christos static void
    505      1.1  christos bfin_emac_attach_address_callback (struct hw *me,
    506      1.1  christos 				   int level,
    507      1.1  christos 				   int space,
    508      1.1  christos 				   address_word addr,
    509      1.1  christos 				   address_word nr_bytes,
    510      1.1  christos 				   struct hw *client)
    511      1.1  christos {
    512      1.1  christos   const hw_unit *unit = hw_unit_address (client);
    513      1.1  christos   HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%lu, client=%s",
    514      1.1  christos 	     level, space, (unsigned long) addr, (unsigned long) nr_bytes, hw_path (client)));
    515      1.1  christos   /* NOTE: At preset the space is assumed to be zero.  Perhaphs the
    516      1.1  christos      space should be mapped onto something for instance: space0 -
    517      1.1  christos      unified memory; space1 - IO memory; ... */
    518      1.1  christos   sim_core_attach (hw_system (me),
    519      1.1  christos 		   NULL, /*cpu*/
    520      1.1  christos 		   level + 10 + unit->cells[unit->nr_cells - 1],
    521      1.1  christos 		   access_read_write_exec,
    522      1.1  christos 		   space, addr,
    523      1.1  christos 		   nr_bytes,
    524      1.1  christos 		   0, /* modulo */
    525      1.1  christos 		   client,
    526      1.1  christos 		   NULL);
    527      1.1  christos }
    528      1.1  christos 
    529      1.1  christos static void
    530      1.1  christos bfin_emac_delete (struct hw *me)
    531      1.1  christos {
    532      1.1  christos   struct bfin_emac *emac = hw_data (me);
    533      1.1  christos   close (emac->tap);
    534      1.1  christos }
    535      1.1  christos 
    536      1.1  christos static void
    537      1.1  christos bfin_emac_tap_init (struct hw *me)
    538      1.1  christos {
    539      1.1  christos #if WITH_TUN
    540      1.1  christos   struct bfin_emac *emac = hw_data (me);
    541      1.1  christos   const hw_unit *unit;
    542      1.1  christos   int flags;
    543      1.1  christos 
    544      1.1  christos   unit = hw_unit_address (me);
    545      1.1  christos 
    546      1.1  christos   emac->tap = open ("/dev/net/tun", O_RDWR);
    547      1.1  christos   if (emac->tap == -1)
    548      1.1  christos     {
    549      1.1  christos       HW_TRACE ((me, "unable to open /dev/net/tun: %s", strerror (errno)));
    550      1.1  christos       return;
    551      1.1  christos     }
    552      1.1  christos 
    553      1.1  christos   memset (&emac->ifr, 0, sizeof (emac->ifr));
    554      1.1  christos   emac->ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
    555      1.1  christos   strcpy (emac->ifr.ifr_name, "tap-gdb");
    556      1.1  christos 
    557      1.1  christos   flags = 1 * 1024 * 1024;
    558      1.1  christos   if (ioctl (emac->tap, TUNSETIFF, &emac->ifr) < 0
    559      1.1  christos #ifdef TUNSETNOCSUM
    560      1.1  christos       || ioctl (emac->tap, TUNSETNOCSUM) < 0
    561      1.1  christos #endif
    562      1.1  christos #ifdef TUNSETSNDBUF
    563      1.1  christos       || ioctl (emac->tap, TUNSETSNDBUF, &flags) < 0
    564      1.1  christos #endif
    565      1.1  christos      )
    566      1.1  christos     {
    567      1.1  christos       HW_TRACE ((me, "tap ioctl setup failed: %s", strerror (errno)));
    568      1.1  christos       close (emac->tap);
    569      1.1  christos       return;
    570      1.1  christos     }
    571      1.1  christos 
    572      1.1  christos   flags = fcntl (emac->tap, F_GETFL);
    573      1.1  christos   fcntl (emac->tap, F_SETFL, flags | O_NONBLOCK);
    574      1.1  christos #endif
    575      1.1  christos }
    576      1.1  christos 
    577      1.1  christos static void
    578      1.1  christos bfin_emac_finish (struct hw *me)
    579      1.1  christos {
    580      1.1  christos   struct bfin_emac *emac;
    581      1.1  christos 
    582      1.1  christos   emac = HW_ZALLOC (me, struct bfin_emac);
    583      1.1  christos 
    584      1.1  christos   set_hw_data (me, emac);
    585      1.1  christos   set_hw_io_read_buffer (me, bfin_emac_io_read_buffer);
    586      1.1  christos   set_hw_io_write_buffer (me, bfin_emac_io_write_buffer);
    587      1.1  christos   set_hw_dma_read_buffer (me, bfin_emac_dma_read_buffer);
    588      1.1  christos   set_hw_dma_write_buffer (me, bfin_emac_dma_write_buffer);
    589      1.1  christos   set_hw_ports (me, bfin_emac_ports);
    590      1.1  christos   set_hw_attach_address (me, bfin_emac_attach_address_callback);
    591      1.1  christos   set_hw_delete (me, bfin_emac_delete);
    592      1.1  christos 
    593      1.1  christos   attach_bfin_emac_regs (me, emac);
    594      1.1  christos 
    595      1.1  christos   /* Initialize the EMAC.  */
    596      1.1  christos   emac->addrlo = 0xffffffff;
    597      1.1  christos   emac->addrhi = 0x0000ffff;
    598      1.1  christos   emac->vlan1 = 0x0000ffff;
    599      1.1  christos   emac->vlan2 = 0x0000ffff;
    600      1.1  christos   emac->sysctl = 0x00003f00;
    601      1.1  christos   emac->mmc_ctl = 0x0000000a;
    602      1.1  christos 
    603      1.1  christos   bfin_emac_tap_init (me);
    604      1.1  christos }
    605      1.1  christos 
    606      1.1  christos const struct hw_descriptor dv_bfin_emac_descriptor[] =
    607      1.1  christos {
    608      1.1  christos   {"bfin_emac", bfin_emac_finish,},
    609      1.1  christos   {NULL, NULL},
    610      1.1  christos };
    611