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