embox

Форк
0
/
xilinx_emaclite.c 
356 строк · 8.5 Кб
1
/**
2
 * @file
3
 * @brief Emaclite driver.
4
 *
5
 * @date 18.12.2009
6
 * @author Anton Bondarev
7
 */
8

9
#include <stdint.h>
10
#include <stddef.h>
11
#include <string.h>
12
#include <errno.h>
13
#include <arpa/inet.h>
14

15
#include <util/log.h>
16
#include <net/util/show_packet.h>
17

18
#include <kernel/irq.h>
19
#include <net/skbuff.h>
20
#include <net/netdevice.h>
21
#include <net/inetdevice.h>
22
#include <net/l2/ethernet.h>
23
#include <net/l0/net_entry.h>
24

25
#include <embox/unit.h>
26
#include <module/embox/driver/net/xemaclite.h>
27

28
#define CONFIG_XILINX_EMACLITE_BASEADDR OPTION_GET(NUMBER,xemaclite_base)
29
#define CONFIG_XILINX_EMACLITE_IRQ_NUM  OPTION_GET(NUMBER,irq_num)
30

31
EMBOX_UNIT_INIT(emaclite_init);
32

33
#define PKTSIZE 0x800
34

35
/* Xmit complete */
36
#define XEL_TSR_XMIT_BUSY_MASK		0x00000001UL
37
/* Xmit interrupt enable bit */
38
#define XEL_TSR_XMIT_IE_MASK		0x00000008UL
39
/* Buffer is active, SW bit only */
40
#define XEL_TSR_XMIT_ACTIVE_MASK	0x80000000UL
41
/* Program the MAC address */
42
#define XEL_TSR_PROGRAM_MASK		0x00000002UL
43
/* define for programming the MAC address into the EMAC Lite */
44
#define XEL_TSR_PROG_MAC_ADDR	(XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_PROGRAM_MASK)
45

46
/* Transmit packet length upper byte */
47
#define XEL_TPLR_LENGTH_MASK_HI		0x0000FF00UL
48
/* Transmit packet length lower byte */
49
#define XEL_TPLR_LENGTH_MASK_LO		0x000000FFUL
50

51
/* Recv complete */
52
#define XEL_RSR_RECV_DONE_MASK		0x00000001UL
53
/* Recv interrupt enable bit */
54
#define XEL_RSR_RECV_IE_MASK		0x00000008UL
55

56
/* Global Interrupt Enable Register (GIER) Bit Masks */
57
#define XEL_GIER_GIE_MASK	0x80000000 	/* Global Enable */
58

59
/* Transmit Packet Length Register (TPLR) */
60
#define XEL_TPLR_LENGTH_MASK	0x0000FFFF 	/* Tx packet length */
61

62
typedef struct mdio_regs {
63
	uint32_t regs;
64
} mdio_regs_t;
65

66
typedef struct pingpong_regs {
67
	uint8_t pack[0x07F0];
68
	mdio_regs_t mdio_regs;
69
	uint32_t len; /*0x07F4*/
70
	uint32_t gie;
71
	uint32_t ctrl;
72
} pingpong_regs_t;
73

74
typedef struct xilinx_emaclite_regs {
75
	pingpong_regs_t tx_ping;
76
	pingpong_regs_t tx_pong;
77
	pingpong_regs_t rx_ping;
78
	pingpong_regs_t rx_pong;
79
} xilinx_emaclite_regs_t;
80

81
static struct xilinx_emaclite_regs *emaclite =
82
		(struct xilinx_emaclite_regs *) CONFIG_XILINX_EMACLITE_BASEADDR;
83
static pingpong_regs_t *current_rx_regs = NULL;
84
static pingpong_regs_t *current_tx_regs = NULL;
85

86
#define GIE_REG      (&emaclite->tx_ping)->gie
87
#define RX_PACK      ((uint8_t *) current_rx_regs->pack)
88
#define TX_PACK      ((uint8_t *) current_tx_regs->pack)
89
#define TX_LEN_REG   current_tx_regs->len
90
#define TX_CTRL_REG  current_tx_regs->ctrl
91
#define RX_CTRL_REG  current_rx_regs->ctrl
92

93
#define PINPONG_BUFFER
94

95
static void switch_rx_buff(void) {
96
#ifdef PINPONG_BUFFER
97
	if (current_rx_regs == &emaclite->rx_ping) {
98
		current_rx_regs = &emaclite->rx_ping;
99
	} else {
100
		current_rx_regs = &emaclite->rx_pong;
101
	}
102
#else
103
	current_rx_regs = &emaclite->rx_ping;
104
#endif
105
}
106

107
static void switch_tx_buff(void) {
108
#ifdef PINPONG_BUFFER
109
	if (current_tx_regs == &emaclite->tx_ping) {
110
		current_tx_regs = &emaclite->tx_ping;
111
	} else {
112
		current_tx_regs = &emaclite->tx_pong;
113
	}
114
#else
115
	current_tx_regs = &emaclite->tx_ping;
116
#endif
117
}
118

119
static void restart_buff(void) {
120
	switch_tx_buff();
121
	TX_LEN_REG = 0;
122
	switch_tx_buff();
123
	TX_LEN_REG = 0;
124
}
125

126
static pingpong_regs_t *get_rx_buff(void) {
127
	if (current_rx_regs->ctrl & XEL_RSR_RECV_DONE_MASK) {
128
		return current_rx_regs;
129
	}
130
	switch_rx_buff();
131
	if (current_rx_regs->ctrl & XEL_RSR_RECV_DONE_MASK) {
132
		return current_rx_regs;
133
	}
134
	return NULL;
135
}
136

137
/*FIXME bad function (may be use if dest and src align 4)*/
138
static void memcpy32(volatile uint32_t *dest, void *src, size_t len) {
139
	size_t lenw = (size_t) ((len & (~3)) >> 2);
140
	volatile uint32_t *srcw = (uint32_t*) ((uint32_t) (src) & (~3));
141

142
	while (lenw--) {
143
		*dest++ = *srcw++;
144
	}
145
	if (len & (~3)) {
146
		*dest++ = *srcw++;
147
	}
148
}
149

150
static uint32_t *word_aligned_addr(void *addr) {
151
	return ((uint32_t *) ((int) addr & ~0x3)) + ((int) addr & 0x3 ? 1 : 0);
152
}
153

154
/**
155
 * Send a packet on this device.
156
 */
157
static int emaclite_xmit(struct net_device *dev, struct sk_buff *skb) {
158
	uint32_t *aligned_data;
159

160
	if ((NULL == skb) || (NULL == dev)) {
161
		return -EINVAL;
162
	}
163

164
	if (NULL == skb_declone(skb)) {
165
		return -ENOMEM;
166
	}
167

168
	if (0 != (TX_CTRL_REG & XEL_TSR_XMIT_BUSY_MASK)) {
169
		switch_tx_buff();
170
		if (0 != (TX_CTRL_REG & XEL_TSR_XMIT_BUSY_MASK)) {
171
			return -EBUSY; /*transmitter is busy*/
172
		}
173
	}
174

175
	aligned_data = word_aligned_addr(skb->mac.raw);
176

177
	if ((int) aligned_data != (int) skb->mac.raw) {
178
		memmove(aligned_data, skb->mac.raw, skb->len);
179
	}
180

181
	memcpy32((uint32_t*) TX_PACK, aligned_data, skb->len);
182
	TX_LEN_REG = skb->len & XEL_TPLR_LENGTH_MASK;
183
	TX_CTRL_REG |= XEL_TSR_XMIT_BUSY_MASK;
184
	show_packet(skb->mac.raw, skb->len, "TX");
185
	skb_free(skb);
186

187
	return 0;
188
}
189

190
/**
191
 *
192
 */
193
static void pack_receiving(void *dev_id) {
194
	uint16_t len, proto_type;
195
	uint32_t tmp;
196
	sk_buff_t *skb;
197
	struct net_device_stats *stats;
198
	int rx_rc;
199

200
	/* Get the protocol type of the ethernet frame that arrived */
201
	tmp = *(volatile uint32_t *) (RX_PACK + 0xC);
202
	proto_type = (tmp >> 0x10) & 0xFFFF;
203

204
	/* Check if received ethernet frame is a raw ethernet frame
205
	 * or an IP packet or an ARP packet */
206
	switch (proto_type) {
207
	case ETH_P_IP:
208
		len = (((*(volatile uint32_t *) (RX_PACK + 0x10))) >> 16) & 0xFFFF;
209
		len += ETH_HLEN + ETH_FCS_LEN;
210
		break;
211
	case ETH_P_ARP:
212
		len = 28 + ETH_HLEN + ETH_FCS_LEN;
213
		break;
214
	default:
215
		/* Field contains type other than IP or ARP, use max
216
		 * frame size and let user parse it */
217
		len = ETH_FRAME_LEN;
218
		break;
219
	}
220

221
	/* Read from the EmacLite device */
222

223
	skb = skb_alloc(len + 4);
224
	if (NULL == skb) {
225
		log_error("Can't allocate packet, pack_pool is full\n");
226
		current_rx_regs->ctrl &= ~XEL_RSR_RECV_DONE_MASK;
227
		switch_rx_buff();
228
		return;
229
	}
230

231
	memcpy32(word_aligned_addr(skb->mac.raw), RX_PACK, (size_t) len);
232
	if ((int) skb->mac.raw & 0x3) {
233
		memmove(skb->mac.raw, word_aligned_addr(skb->mac.raw), len);
234
	}
235

236
	skb->len -= 8;
237
	/* Acknowledge the frame */
238
	current_rx_regs->ctrl &= ~XEL_RSR_RECV_DONE_MASK;
239

240
	/* update device statistic */
241
	skb->dev = dev_id;
242
	stats = &skb->dev->stats;
243
	stats->rx_packets++;
244
	stats->rx_bytes += skb->len;
245

246
	show_packet(skb->mac.raw, skb->len, "RX");
247
	rx_rc = netif_rx(skb);
248
	if (NET_RX_DROP == rx_rc) {
249
		stats->rx_dropped++;
250
	}
251
}
252

253
/**
254
 * IRQ handler
255
 */
256
static irq_return_t emaclite_irq_handler(unsigned int irq_num, void *dev_id) {
257
	while (NULL != get_rx_buff()) {
258
		pack_receiving(dev_id);
259
	}
260
	return IRQ_HANDLED;
261
}
262
/*default 00-00-5E-00-FA-CE*/
263
static const unsigned char default_mac[ETH_ALEN] = { 0x00, 0x00, 0x5E, 0x00, 0xFA,
264
		0xCE };
265

266
static int emaclite_open(struct net_device *dev) {
267
	if (NULL == dev) {
268
		return -EINVAL;
269
	}
270

271
	current_rx_regs = &emaclite->rx_ping;
272
	current_tx_regs = &emaclite->tx_ping;
273
	/*
274
	 * TX - TX_PING & TX_PONG initialization
275
	 */
276
	/* Restart PING TX */
277

278
	restart_buff();
279
	/* Copy MAC address */
280
	memcpy(dev->dev_addr, default_mac, ETH_ALEN);
281
#if 0
282
	/*default 00-00-5E-00-FA-CE*/
283
	set_mac_address(dev, dev->hw_addr);
284
#endif
285

286
	/*
287
	 * RX - RX_PING & RX_PONG initialization
288
	 */
289
	RX_CTRL_REG = XEL_RSR_RECV_IE_MASK;
290
#ifdef PINPONG_BUFFER
291
	switch_rx_buff();
292
	RX_CTRL_REG = XEL_RSR_RECV_IE_MASK;
293
	switch_rx_buff();
294
#endif
295

296
	GIE_REG = XEL_GIER_GIE_MASK;
297
	return ENOERR;
298
}
299

300
static int emaclite_stop(struct net_device *dev) {
301
	if (NULL == dev) {
302
		return -EINVAL;
303
	}
304

305
	return ENOERR;
306
}
307

308
static int emaclite_set_mac_address(struct net_device *dev, const void *addr) {
309
	if (NULL == dev || NULL == addr) {
310
		return -EINVAL;
311
	}
312
#if 0
313
	out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, 0);
314
	/* Set the length */
315
	out_be32 (emaclite.baseaddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
316
	/* Update the MAC address in the EMAC Lite */
317
	out_be32 (emaclite.baseaddress + XEL_TSR_OFFSET, XEL_TSR_PROG_MAC_ADDR);
318
	/* Wait for EMAC Lite to finish with the MAC address update */
319
	while ((in_be32 (emaclite.baseaddress + XEL_TSR_OFFSET) &
320
					XEL_TSR_PROG_MAC_ADDR) != 0);
321
#endif
322
	return ENOERR;
323
}
324

325
/*
326
 * Get RX/TX stats
327
 */
328
static const struct net_driver _drv_ops = {
329
	.xmit = emaclite_xmit,
330
	.start = emaclite_open,
331
	.stop = emaclite_stop,
332
	.set_macaddr = emaclite_set_mac_address
333
};
334

335
static int emaclite_init(void) {
336
	/*if some module lock irq number we break initializing*/
337
	int res;
338
	struct net_device *net_device;
339
	/*initialize net_device structures and save
340
	 * information about them to local massive */
341
	net_device = etherdev_alloc(0);
342
	if (net_device == NULL) {
343
		return -ENOMEM;
344
	}
345
	net_device->drv_ops = &_drv_ops;
346
	net_device->irq = CONFIG_XILINX_EMACLITE_IRQ_NUM;
347
	net_device->base_addr = CONFIG_XILINX_EMACLITE_BASEADDR;
348

349
	res = irq_attach(CONFIG_XILINX_EMACLITE_IRQ_NUM, emaclite_irq_handler, 0,
350
			net_device, "xilinx emaclite");
351
	if (res != 0) {
352
		return res;
353
	}
354

355
	return inetdev_register_dev(net_device);
356
}
357

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.