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, ®)) 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 ®.address, 358 1.1 christos &attach_space, &attach_address, me); 359 1.1 christos hw_unit_size_to_attach_size (hw_parent (me), ®.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