dv-bfin_emac.c revision 1.10 1 1.1 christos /* Blackfin Ethernet Media Access Controller (EMAC) model.
2 1.1 christos
3 1.10 christos Copyright (C) 2010-2023 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 const hw_unit *unit;
543 1.1 christos int flags;
544 1.1 christos
545 1.1 christos unit = hw_unit_address (me);
546 1.1 christos
547 1.1 christos emac->tap = open ("/dev/net/tun", O_RDWR);
548 1.1 christos if (emac->tap == -1)
549 1.1 christos {
550 1.1 christos HW_TRACE ((me, "unable to open /dev/net/tun: %s", strerror (errno)));
551 1.1 christos return;
552 1.1 christos }
553 1.1 christos
554 1.1 christos memset (&emac->ifr, 0, sizeof (emac->ifr));
555 1.1 christos emac->ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
556 1.1 christos strcpy (emac->ifr.ifr_name, "tap-gdb");
557 1.1 christos
558 1.1 christos flags = 1 * 1024 * 1024;
559 1.1 christos if (ioctl (emac->tap, TUNSETIFF, &emac->ifr) < 0
560 1.1 christos #ifdef TUNSETNOCSUM
561 1.1 christos || ioctl (emac->tap, TUNSETNOCSUM) < 0
562 1.1 christos #endif
563 1.1 christos #ifdef TUNSETSNDBUF
564 1.1 christos || ioctl (emac->tap, TUNSETSNDBUF, &flags) < 0
565 1.1 christos #endif
566 1.1 christos )
567 1.1 christos {
568 1.1 christos HW_TRACE ((me, "tap ioctl setup failed: %s", strerror (errno)));
569 1.1 christos close (emac->tap);
570 1.1 christos return;
571 1.1 christos }
572 1.1 christos
573 1.1 christos flags = fcntl (emac->tap, F_GETFL);
574 1.1 christos fcntl (emac->tap, F_SETFL, flags | O_NONBLOCK);
575 1.1 christos #endif
576 1.1 christos }
577 1.1 christos
578 1.1 christos static void
579 1.1 christos bfin_emac_finish (struct hw *me)
580 1.1 christos {
581 1.1 christos struct bfin_emac *emac;
582 1.1 christos
583 1.1 christos emac = HW_ZALLOC (me, struct bfin_emac);
584 1.1 christos
585 1.1 christos set_hw_data (me, emac);
586 1.1 christos set_hw_io_read_buffer (me, bfin_emac_io_read_buffer);
587 1.1 christos set_hw_io_write_buffer (me, bfin_emac_io_write_buffer);
588 1.1 christos set_hw_dma_read_buffer (me, bfin_emac_dma_read_buffer);
589 1.1 christos set_hw_dma_write_buffer (me, bfin_emac_dma_write_buffer);
590 1.1 christos set_hw_ports (me, bfin_emac_ports);
591 1.1 christos set_hw_attach_address (me, bfin_emac_attach_address_callback);
592 1.1 christos set_hw_delete (me, bfin_emac_delete);
593 1.1 christos
594 1.1 christos attach_bfin_emac_regs (me, emac);
595 1.1 christos
596 1.1 christos /* Initialize the EMAC. */
597 1.1 christos emac->addrlo = 0xffffffff;
598 1.1 christos emac->addrhi = 0x0000ffff;
599 1.1 christos emac->vlan1 = 0x0000ffff;
600 1.1 christos emac->vlan2 = 0x0000ffff;
601 1.1 christos emac->sysctl = 0x00003f00;
602 1.1 christos emac->mmc_ctl = 0x0000000a;
603 1.1 christos
604 1.1 christos bfin_emac_tap_init (me);
605 1.1 christos }
606 1.1 christos
607 1.1 christos const struct hw_descriptor dv_bfin_emac_descriptor[] =
608 1.1 christos {
609 1.1 christos {"bfin_emac", bfin_emac_finish,},
610 1.1 christos {NULL, NULL},
611 1.1 christos };
612