dv-bfin_emac.c revision 1.1.1.1 1 1.1 christos /* Blackfin Ethernet Media Access Controller (EMAC) model.
2 1.1 christos
3 1.1 christos Copyright (C) 2010-2014 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 christos /* XXX: 16bit accesses are allowed ... */
181 1.1 christos dv_bfin_mmr_require_32 (me, addr, nr_bytes, true);
182 1.1 christos value = dv_load_4 (source);
183 1.1 christos
184 1.1 christos mmr_off = addr - emac->base;
185 1.1 christos valuep = (void *)((unsigned long)emac + mmr_base() + mmr_off);
186 1.1 christos
187 1.1 christos HW_TRACE_WRITE ();
188 1.1 christos
189 1.1 christos switch (mmr_off)
190 1.1 christos {
191 1.1 christos case mmr_offset(hashlo):
192 1.1 christos case mmr_offset(hashhi):
193 1.1 christos case mmr_offset(stadat):
194 1.1 christos case mmr_offset(flc):
195 1.1 christos case mmr_offset(vlan1):
196 1.1 christos case mmr_offset(vlan2):
197 1.1 christos case mmr_offset(wkup_ffmsk0):
198 1.1 christos case mmr_offset(wkup_ffmsk1):
199 1.1 christos case mmr_offset(wkup_ffmsk2):
200 1.1 christos case mmr_offset(wkup_ffmsk3):
201 1.1 christos case mmr_offset(wkup_ffcmd):
202 1.1 christos case mmr_offset(wkup_ffoff):
203 1.1 christos case mmr_offset(wkup_ffcrc0):
204 1.1 christos case mmr_offset(wkup_ffcrc1):
205 1.1 christos case mmr_offset(sysctl):
206 1.1 christos case mmr_offset(rx_irqe):
207 1.1 christos case mmr_offset(tx_irqe):
208 1.1 christos case mmr_offset(mmc_rirqe):
209 1.1 christos case mmr_offset(mmc_tirqe):
210 1.1 christos *valuep = value;
211 1.1 christos break;
212 1.1 christos case mmr_offset(opmode):
213 1.1 christos if (!(*valuep & RE) && (value & RE))
214 1.1 christos emac->rx_stat &= ~RX_COMP;
215 1.1 christos if (!(*valuep & TE) && (value & TE))
216 1.1 christos emac->tx_stat &= ~TX_COMP;
217 1.1 christos *valuep = value;
218 1.1 christos break;
219 1.1 christos case mmr_offset(addrlo):
220 1.1 christos case mmr_offset(addrhi):
221 1.1 christos *valuep = value;
222 1.1 christos break;
223 1.1 christos case mmr_offset(wkup_ctl):
224 1.1 christos dv_w1c_4_partial (valuep, value, 0xf20);
225 1.1 christos break;
226 1.1 christos case mmr_offset(systat):
227 1.1 christos dv_w1c_4 (valuep, value, 0xe1);
228 1.1 christos break;
229 1.1 christos case mmr_offset(staadd):
230 1.1 christos *valuep = value | STABUSY;
231 1.1 christos if (value & STAOP)
232 1.1 christos mii_write (me);
233 1.1 christos else
234 1.1 christos mii_read (me);
235 1.1 christos *valuep &= ~STABUSY;
236 1.1 christos break;
237 1.1 christos case mmr_offset(rx_stat):
238 1.1 christos case mmr_offset(tx_stat):
239 1.1 christos /* Discard writes to these. */
240 1.1 christos break;
241 1.1 christos case mmr_offset(rx_stky):
242 1.1 christos case mmr_offset(tx_stky):
243 1.1 christos case mmr_offset(mmc_rirqs):
244 1.1 christos case mmr_offset(mmc_tirqs):
245 1.1 christos dv_w1c_4 (valuep, value, -1);
246 1.1 christos break;
247 1.1 christos case mmr_offset(mmc_ctl):
248 1.1 christos /* Writing to bit 0 clears all counters. */
249 1.1 christos *valuep = value & ~1;
250 1.1 christos if (value & 1)
251 1.1 christos {
252 1.1 christos memset (&emac->rxc_ok, 0, mmr_offset (rxc_ge1024) - mmr_offset (rxc_ok) + 4);
253 1.1 christos memset (&emac->txc_ok, 0, mmr_offset (txc_abort) - mmr_offset (txc_ok) + 4);
254 1.1 christos }
255 1.1 christos break;
256 1.1 christos case mmr_offset(rxc_ok) ... mmr_offset(rxc_ge1024):
257 1.1 christos case mmr_offset(txc_ok) ... mmr_offset(txc_abort):
258 1.1 christos /* XXX: Are these supposed to be read-only ? */
259 1.1 christos *valuep = value;
260 1.1 christos break;
261 1.1 christos case mmr_offset(ptp_ctl) ... mmr_offset(ptp_pps_period):
262 1.1 christos /* XXX: Only on some models; ignore for now. */
263 1.1 christos break;
264 1.1 christos default:
265 1.1 christos dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
266 1.1 christos break;
267 1.1 christos }
268 1.1 christos
269 1.1 christos return nr_bytes;
270 1.1 christos }
271 1.1 christos
272 1.1 christos static unsigned
273 1.1 christos bfin_emac_io_read_buffer (struct hw *me, void *dest,
274 1.1 christos int space, address_word addr, unsigned nr_bytes)
275 1.1 christos {
276 1.1 christos struct bfin_emac *emac = hw_data (me);
277 1.1 christos bu32 mmr_off;
278 1.1 christos bu32 *valuep;
279 1.1 christos
280 1.1 christos /* XXX: 16bit accesses are allowed ... */
281 1.1 christos dv_bfin_mmr_require_32 (me, addr, nr_bytes, false);
282 1.1 christos
283 1.1 christos mmr_off = addr - emac->base;
284 1.1 christos valuep = (void *)((unsigned long)emac + mmr_base() + mmr_off);
285 1.1 christos
286 1.1 christos HW_TRACE_READ ();
287 1.1 christos
288 1.1 christos switch (mmr_off)
289 1.1 christos {
290 1.1 christos case mmr_offset(opmode):
291 1.1 christos case mmr_offset(addrlo):
292 1.1 christos case mmr_offset(addrhi):
293 1.1 christos case mmr_offset(hashlo):
294 1.1 christos case mmr_offset(hashhi):
295 1.1 christos case mmr_offset(staadd):
296 1.1 christos case mmr_offset(stadat):
297 1.1 christos case mmr_offset(flc):
298 1.1 christos case mmr_offset(vlan1):
299 1.1 christos case mmr_offset(vlan2):
300 1.1 christos case mmr_offset(wkup_ctl):
301 1.1 christos case mmr_offset(wkup_ffmsk0):
302 1.1 christos case mmr_offset(wkup_ffmsk1):
303 1.1 christos case mmr_offset(wkup_ffmsk2):
304 1.1 christos case mmr_offset(wkup_ffmsk3):
305 1.1 christos case mmr_offset(wkup_ffcmd):
306 1.1 christos case mmr_offset(wkup_ffoff):
307 1.1 christos case mmr_offset(wkup_ffcrc0):
308 1.1 christos case mmr_offset(wkup_ffcrc1):
309 1.1 christos case mmr_offset(sysctl):
310 1.1 christos case mmr_offset(systat):
311 1.1 christos case mmr_offset(rx_stat):
312 1.1 christos case mmr_offset(rx_stky):
313 1.1 christos case mmr_offset(rx_irqe):
314 1.1 christos case mmr_offset(tx_stat):
315 1.1 christos case mmr_offset(tx_stky):
316 1.1 christos case mmr_offset(tx_irqe):
317 1.1 christos case mmr_offset(mmc_rirqs):
318 1.1 christos case mmr_offset(mmc_rirqe):
319 1.1 christos case mmr_offset(mmc_tirqs):
320 1.1 christos case mmr_offset(mmc_tirqe):
321 1.1 christos case mmr_offset(mmc_ctl):
322 1.1 christos case mmr_offset(rxc_ok) ... mmr_offset(rxc_ge1024):
323 1.1 christos case mmr_offset(txc_ok) ... mmr_offset(txc_abort):
324 1.1 christos dv_store_4 (dest, *valuep);
325 1.1 christos break;
326 1.1 christos case mmr_offset(ptp_ctl) ... mmr_offset(ptp_pps_period):
327 1.1 christos /* XXX: Only on some models; ignore for now. */
328 1.1 christos break;
329 1.1 christos default:
330 1.1 christos dv_bfin_mmr_invalid (me, addr, nr_bytes, false);
331 1.1 christos break;
332 1.1 christos }
333 1.1 christos
334 1.1 christos return nr_bytes;
335 1.1 christos }
336 1.1 christos
337 1.1 christos static void
338 1.1 christos attach_bfin_emac_regs (struct hw *me, struct bfin_emac *emac)
339 1.1 christos {
340 1.1 christos address_word attach_address;
341 1.1 christos int attach_space;
342 1.1 christos unsigned attach_size;
343 1.1 christos reg_property_spec reg;
344 1.1 christos
345 1.1 christos if (hw_find_property (me, "reg") == NULL)
346 1.1 christos hw_abort (me, "Missing \"reg\" property");
347 1.1 christos
348 1.1 christos if (!hw_find_reg_array_property (me, "reg", 0, ®))
349 1.1 christos hw_abort (me, "\"reg\" property must contain three addr/size entries");
350 1.1 christos
351 1.1 christos hw_unit_address_to_attach_address (hw_parent (me),
352 1.1 christos ®.address,
353 1.1 christos &attach_space, &attach_address, me);
354 1.1 christos hw_unit_size_to_attach_size (hw_parent (me), ®.size, &attach_size, me);
355 1.1 christos
356 1.1 christos if (attach_size != BFIN_MMR_EMAC_SIZE)
357 1.1 christos hw_abort (me, "\"reg\" size must be %#x", BFIN_MMR_EMAC_SIZE);
358 1.1 christos
359 1.1 christos hw_attach_address (hw_parent (me),
360 1.1 christos 0, attach_space, attach_address, attach_size, me);
361 1.1 christos
362 1.1 christos emac->base = attach_address;
363 1.1 christos }
364 1.1 christos
365 1.1 christos static struct dv_bfin *dma_tx;
366 1.1 christos
367 1.1 christos static unsigned
368 1.1 christos bfin_emac_dma_read_buffer (struct hw *me, void *dest, int space,
369 1.1 christos unsigned_word addr, unsigned nr_bytes)
370 1.1 christos {
371 1.1 christos struct bfin_emac *emac = hw_data (me);
372 1.1 christos struct dv_bfin *dma = hw_data (emac->dma_master);
373 1.1 christos unsigned char *data = dest;
374 1.1 christos static bool flop; /* XXX: This sucks. */
375 1.1 christos bu16 len;
376 1.1 christos ssize_t ret;
377 1.1 christos
378 1.1 christos HW_TRACE_DMA_READ ();
379 1.1 christos
380 1.1 christos if (dma_tx == dma)
381 1.1 christos {
382 1.1 christos /* Handle the TX turn around and write the status. */
383 1.1 christos emac->tx_stat |= TX_OK;
384 1.1 christos emac->tx_stky |= TX_OK;
385 1.1 christos
386 1.1 christos memcpy (data, &emac->tx_stat, 4);
387 1.1 christos
388 1.1 christos dma->acked = true;
389 1.1 christos return 4;
390 1.1 christos }
391 1.1 christos
392 1.1 christos if (!(emac->opmode & RE))
393 1.1 christos return 0;
394 1.1 christos
395 1.1 christos if (!flop)
396 1.1 christos {
397 1.1 christos ssize_t pad_ret;
398 1.1 christos /* Outgoing DMA buffer has 16bit len prepended to it. */
399 1.1 christos data += 2;
400 1.1 christos
401 1.1 christos /* This doesn't seem to work.
402 1.1 christos if (emac->sysctl & RXDWA)
403 1.1 christos {
404 1.1 christos memset (data, 0, 2);
405 1.1 christos data += 2;
406 1.1 christos } */
407 1.1 christos
408 1.1 christos ret = read (emac->tap, data, nr_bytes);
409 1.1 christos if (ret < 0)
410 1.1 christos return 0;
411 1.1 christos ret += 4; /* include crc */
412 1.1 christos pad_ret = MAX (ret + 4, 64);
413 1.1 christos len = pad_ret;
414 1.1 christos memcpy (dest, &len, 2);
415 1.1 christos
416 1.1 christos pad_ret = (pad_ret + 3) & ~3;
417 1.1 christos if (ret < pad_ret)
418 1.1 christos memset (data + ret, 0, pad_ret - ret);
419 1.1 christos pad_ret += 4;
420 1.1 christos
421 1.1 christos /* XXX: Need to check -- u-boot doesn't look at this. */
422 1.1 christos if (emac->sysctl & RXCKS)
423 1.1 christos {
424 1.1 christos pad_ret += 4;
425 1.1 christos emac->rx_crc = 0;
426 1.1 christos }
427 1.1 christos ret = pad_ret;
428 1.1 christos
429 1.1 christos /* XXX: Don't support promiscuous yet. */
430 1.1 christos emac->rx_stat |= RX_ACCEPT;
431 1.1 christos emac->rx_stat = (emac->rx_stat & ~RX_FRLEN) | len;
432 1.1 christos
433 1.1 christos emac->rx_stat |= RX_COMP;
434 1.1 christos emac->rx_stky |= RX_COMP;
435 1.1 christos }
436 1.1 christos else
437 1.1 christos {
438 1.1 christos /* Write the RX status and crc info. */
439 1.1 christos emac->rx_stat |= RX_OK;
440 1.1 christos emac->rx_stky |= RX_OK;
441 1.1 christos
442 1.1 christos ret = 4;
443 1.1 christos if (emac->sysctl & RXCKS)
444 1.1 christos {
445 1.1 christos memcpy (data, &emac->rx_crc, 4);
446 1.1 christos data += 4;
447 1.1 christos ret += 4;
448 1.1 christos }
449 1.1 christos memcpy (data, &emac->rx_stat, 4);
450 1.1 christos }
451 1.1 christos
452 1.1 christos flop = !flop;
453 1.1 christos dma->acked = true;
454 1.1 christos return ret;
455 1.1 christos }
456 1.1 christos
457 1.1 christos static unsigned
458 1.1 christos bfin_emac_dma_write_buffer (struct hw *me, const void *source,
459 1.1 christos int space, unsigned_word addr,
460 1.1 christos unsigned nr_bytes,
461 1.1 christos int violate_read_only_section)
462 1.1 christos {
463 1.1 christos struct bfin_emac *emac = hw_data (me);
464 1.1 christos struct dv_bfin *dma = hw_data (emac->dma_master);
465 1.1 christos const unsigned char *data = source;
466 1.1 christos bu16 len;
467 1.1 christos ssize_t ret;
468 1.1 christos
469 1.1 christos HW_TRACE_DMA_WRITE ();
470 1.1 christos
471 1.1 christos if (!(emac->opmode & TE))
472 1.1 christos return 0;
473 1.1 christos
474 1.1 christos /* Incoming DMA buffer has 16bit len prepended to it. */
475 1.1 christos memcpy (&len, data, 2);
476 1.1 christos if (!len)
477 1.1 christos return 0;
478 1.1 christos
479 1.1 christos ret = write (emac->tap, data + 2, len);
480 1.1 christos if (ret < 0)
481 1.1 christos return 0;
482 1.1 christos ret += 2;
483 1.1 christos
484 1.1 christos emac->tx_stat |= TX_COMP;
485 1.1 christos emac->tx_stky |= TX_COMP;
486 1.1 christos
487 1.1 christos dma_tx = dma;
488 1.1 christos dma->acked = true;
489 1.1 christos return ret;
490 1.1 christos }
491 1.1 christos
492 1.1 christos static const struct hw_port_descriptor bfin_emac_ports[] =
493 1.1 christos {
494 1.1 christos { "tx", DV_PORT_TX, 0, output_port, },
495 1.1 christos { "rx", DV_PORT_RX, 0, output_port, },
496 1.1 christos { "stat", DV_PORT_STAT, 0, output_port, },
497 1.1 christos { NULL, 0, 0, 0, },
498 1.1 christos };
499 1.1 christos
500 1.1 christos static void
501 1.1 christos bfin_emac_attach_address_callback (struct hw *me,
502 1.1 christos int level,
503 1.1 christos int space,
504 1.1 christos address_word addr,
505 1.1 christos address_word nr_bytes,
506 1.1 christos struct hw *client)
507 1.1 christos {
508 1.1 christos const hw_unit *unit = hw_unit_address (client);
509 1.1 christos HW_TRACE ((me, "attach - level=%d, space=%d, addr=0x%lx, nr_bytes=%lu, client=%s",
510 1.1 christos level, space, (unsigned long) addr, (unsigned long) nr_bytes, hw_path (client)));
511 1.1 christos /* NOTE: At preset the space is assumed to be zero. Perhaphs the
512 1.1 christos space should be mapped onto something for instance: space0 -
513 1.1 christos unified memory; space1 - IO memory; ... */
514 1.1 christos sim_core_attach (hw_system (me),
515 1.1 christos NULL, /*cpu*/
516 1.1 christos level + 10 + unit->cells[unit->nr_cells - 1],
517 1.1 christos access_read_write_exec,
518 1.1 christos space, addr,
519 1.1 christos nr_bytes,
520 1.1 christos 0, /* modulo */
521 1.1 christos client,
522 1.1 christos NULL);
523 1.1 christos }
524 1.1 christos
525 1.1 christos static void
526 1.1 christos bfin_emac_delete (struct hw *me)
527 1.1 christos {
528 1.1 christos struct bfin_emac *emac = hw_data (me);
529 1.1 christos close (emac->tap);
530 1.1 christos }
531 1.1 christos
532 1.1 christos static void
533 1.1 christos bfin_emac_tap_init (struct hw *me)
534 1.1 christos {
535 1.1 christos #if WITH_TUN
536 1.1 christos struct bfin_emac *emac = hw_data (me);
537 1.1 christos const hw_unit *unit;
538 1.1 christos int flags;
539 1.1 christos
540 1.1 christos unit = hw_unit_address (me);
541 1.1 christos
542 1.1 christos emac->tap = open ("/dev/net/tun", O_RDWR);
543 1.1 christos if (emac->tap == -1)
544 1.1 christos {
545 1.1 christos HW_TRACE ((me, "unable to open /dev/net/tun: %s", strerror (errno)));
546 1.1 christos return;
547 1.1 christos }
548 1.1 christos
549 1.1 christos memset (&emac->ifr, 0, sizeof (emac->ifr));
550 1.1 christos emac->ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
551 1.1 christos strcpy (emac->ifr.ifr_name, "tap-gdb");
552 1.1 christos
553 1.1 christos flags = 1 * 1024 * 1024;
554 1.1 christos if (ioctl (emac->tap, TUNSETIFF, &emac->ifr) < 0
555 1.1 christos #ifdef TUNSETNOCSUM
556 1.1 christos || ioctl (emac->tap, TUNSETNOCSUM) < 0
557 1.1 christos #endif
558 1.1 christos #ifdef TUNSETSNDBUF
559 1.1 christos || ioctl (emac->tap, TUNSETSNDBUF, &flags) < 0
560 1.1 christos #endif
561 1.1 christos )
562 1.1 christos {
563 1.1 christos HW_TRACE ((me, "tap ioctl setup failed: %s", strerror (errno)));
564 1.1 christos close (emac->tap);
565 1.1 christos return;
566 1.1 christos }
567 1.1 christos
568 1.1 christos flags = fcntl (emac->tap, F_GETFL);
569 1.1 christos fcntl (emac->tap, F_SETFL, flags | O_NONBLOCK);
570 1.1 christos #endif
571 1.1 christos }
572 1.1 christos
573 1.1 christos static void
574 1.1 christos bfin_emac_finish (struct hw *me)
575 1.1 christos {
576 1.1 christos struct bfin_emac *emac;
577 1.1 christos
578 1.1 christos emac = HW_ZALLOC (me, struct bfin_emac);
579 1.1 christos
580 1.1 christos set_hw_data (me, emac);
581 1.1 christos set_hw_io_read_buffer (me, bfin_emac_io_read_buffer);
582 1.1 christos set_hw_io_write_buffer (me, bfin_emac_io_write_buffer);
583 1.1 christos set_hw_dma_read_buffer (me, bfin_emac_dma_read_buffer);
584 1.1 christos set_hw_dma_write_buffer (me, bfin_emac_dma_write_buffer);
585 1.1 christos set_hw_ports (me, bfin_emac_ports);
586 1.1 christos set_hw_attach_address (me, bfin_emac_attach_address_callback);
587 1.1 christos set_hw_delete (me, bfin_emac_delete);
588 1.1 christos
589 1.1 christos attach_bfin_emac_regs (me, emac);
590 1.1 christos
591 1.1 christos /* Initialize the EMAC. */
592 1.1 christos emac->addrlo = 0xffffffff;
593 1.1 christos emac->addrhi = 0x0000ffff;
594 1.1 christos emac->vlan1 = 0x0000ffff;
595 1.1 christos emac->vlan2 = 0x0000ffff;
596 1.1 christos emac->sysctl = 0x00003f00;
597 1.1 christos emac->mmc_ctl = 0x0000000a;
598 1.1 christos
599 1.1 christos bfin_emac_tap_init (me);
600 1.1 christos }
601 1.1 christos
602 1.1 christos const struct hw_descriptor dv_bfin_emac_descriptor[] =
603 1.1 christos {
604 1.1 christos {"bfin_emac", bfin_emac_finish,},
605 1.1 christos {NULL, NULL},
606 1.1 christos };
607