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