embox

Форк
0
/
lan91c111.c 
329 строк · 6.3 Кб
1
/**
2
 * @file
3
 *
4
 * @date 09.04.2016
5
 * @author: Anton Bondarev
6
 */
7
#include <errno.h>
8
#include <sys/mman.h>
9

10
#include <util/log.h>
11
#include <drivers/common/memory.h>
12

13
#include <kernel/irq.h>
14
#include <mem/misc/pool.h>
15
#include <hal/reg.h>
16

17
#include <net/inetdevice.h>
18
#include <net/l0/net_entry.h>
19
#include <net/l2/ethernet.h>
20
#include <net/netdevice.h>
21
#include <net/skbuff.h>
22
#include <net/util/show_packet.h>
23

24
#include "lan91c111.h"
25

26
#include <embox/unit.h>
27

28
EMBOX_UNIT_INIT(lan91c111_init);
29

30
/* Internal I/O space mapping */
31

32
#define BANK_BASE_ADDR OPTION_GET(NUMBER,base_addr)
33

34
struct smc_local {
35
	struct sk_buff_head pending_queue;
36
};
37

38
/**
39
 * @brief Set active bank ID
40
 */
41
static void lan91c111_set_bank(int n) {
42
	static int cur_bank = -1;
43

44
	assert(0 <= n && n <= 3);
45

46
	if (cur_bank != n) {
47
		REG16_STORE(BANK_BANK, (uint16_t) n);
48
		cur_bank = n;
49
	}
50
}
51

52
/**
53
 * @brief Set appropriate opcode
54
 */
55
static void lan91c111_set_cmd(int opcode) {
56
	assert(0 <= opcode && opcode <= 7);
57

58
	lan91c111_set_bank(2);
59
	if (opcode == CMD_RX_POP_AND_RELEASE) {
60
		/* MMU is busy by another release cmd */
61
		while (REG16_LOAD(BANK_MMU_CMD) & MMU_BUSY) { }
62
	}
63

64
	REG16_STORE(BANK_MMU_CMD, opcode << 5);
65
}
66

67
static void lan91c111_push_data(uint8_t *data, int len) {
68
	int i;
69

70
	for (i = 0; i < len >> 2; i++) {
71
		REG32_STORE(BANK_DATA, *((uint32_t*)data));
72
		data += 4;
73
	}
74

75
	for (i = 0; i < len % 4; i++) {
76
		REG8_STORE(BANK_DATA, *data);
77
		data++;
78
	}
79
}
80

81
static int lan91c111_send_hw(struct sk_buff *skb) {
82
	uint8_t packet_num;
83
	uint16_t packet_len;
84
	uint8_t *data;
85

86
	lan91c111_set_bank(2);
87

88
	packet_num = REG8_LOAD(BANK_TX_ALLOC) & PNUM_MASK;
89

90
	REG8_STORE(BANK_PNR, packet_num);
91

92
	/* Write header */
93
	REG16_STORE(BANK_POINTER, AUTO_INCR | LAN91C111_STATUS_BYTES);
94
	packet_len = (uint16_t) skb->len;
95
	packet_len += LAN91C111_STATUS_BYTES +
96
		sizeof(packet_len) + LAN91C111_CTL_BYTES;
97
	packet_len &= PLEN_MASK;
98
	REG16_STORE(BANK_DATA, packet_len);
99

100
	data = (uint8_t *)skb_data_cast_in(skb->data);
101
	lan91c111_push_data(data, skb->len);
102

103
	if (skb->len % 2) {
104
		REG8_STORE(BANK_DATA, ODD_CONTROL);
105
	} else {
106
		REG16_STORE(BANK_DATA, 0x0);
107
	}
108

109
	lan91c111_set_cmd(CMD_TX_ENQUEUE);
110

111
	return 0;
112
}
113

114
static int lan91c111_add_pending(struct smc_local *smc, struct sk_buff *skb) {
115
	uint8_t int_mask;
116

117
	lan91c111_set_bank(2);
118

119
	skb_queue_push(&smc->pending_queue, skb);
120

121
	int_mask = REG8_LOAD(BANK_INTERRUPT_MASK);
122
	int_mask |= ALLOC_INT;
123
	REG8_STORE(BANK_INTERRUPT_MASK, int_mask);
124

125
	return 0;
126
}
127

128
static int lan91c111_tx_try(struct smc_local *smc, struct sk_buff *skb) {
129
	lan91c111_set_cmd(CMD_TX_ALLOC);
130

131
	lan91c111_set_bank(2);
132

133
	if (!(REG8_LOAD(BANK_INTERRUPT_STATUS) & ALLOC_MASK)) {
134
		lan91c111_add_pending(smc, skb);
135
		return -EBUSY;
136
	}
137

138
	lan91c111_send_hw(skb);
139

140
	return 0;
141
}
142

143
static int lan91c111_xmit(struct net_device *dev, struct sk_buff *skb) {
144
	struct smc_local *smc;
145
	int ret = 0;
146
	ipl_t ipl;
147

148
	smc = netdev_priv(dev);
149

150
	ipl = ipl_save();
151
	{
152
		if (skb_queue_front(&smc->pending_queue)) {
153
			lan91c111_add_pending(smc, skb);
154
			goto out;
155
		}
156

157
		ret = lan91c111_tx_try(smc, skb);
158
		if (ret) {
159
			goto out;
160
		}
161

162
		skb_free(skb);
163
	}
164
out:
165
	ipl_restore(ipl);
166

167
	return 0;
168
}
169

170
static int lan91c111_open(struct net_device *dev) {
171
	lan91c111_set_bank(0);
172
	REG16_STORE(BANK_RCR, RX_EN);
173
	REG16_STORE(BANK_TCR, TX_EN);
174

175
	lan91c111_set_bank(2);
176
	REG8_STORE(BANK_INTERRUPT_MASK, RX_INT);
177

178
	return 0;
179
}
180

181
static int lan91c111_set_macaddr(struct net_device *dev, const void *addr) {
182
	uint8_t *mac = (uint8_t*) addr;
183
	uint16_t mac_hi, mac_mid, mac_lo;
184

185
	assert(mac);
186

187
	mac_hi = (mac[5] << 8) | (mac[4] << 0);
188
	mac_mid = (mac[3] << 8) | (mac[2] << 0);
189
	mac_lo = (mac[1] << 8) | (mac[0] << 0);
190

191
	lan91c111_set_bank(1);
192

193
	REG16_STORE(BANK_IA01, mac_lo);
194
	REG16_STORE(BANK_IA23, mac_mid);
195
	REG16_STORE(BANK_IA45, mac_hi);
196

197
	return 0;
198
}
199

200
static const struct net_driver lan91c111_drv_ops = {
201
	.xmit = lan91c111_xmit,
202
	.start = lan91c111_open,
203
	.set_macaddr = lan91c111_set_macaddr
204
};
205

206
static int lan91c111_tx_pend(struct net_device *dev) {
207
	struct sk_buff *skb;
208
	struct smc_local *smc;
209
	int ret;
210

211
	smc = netdev_priv(dev);
212

213
	while (NULL != (skb = skb_queue_pop(&smc->pending_queue))) {
214
		ret = lan91c111_send_hw(skb);
215
		if (ret) {
216
			return ret;
217
		}
218
		skb_free(skb);
219
	}
220

221
	return 0;
222
}
223

224
static int lan91c111_recv_hw(struct net_device *dev_id) {
225
	int i, packet;
226
	struct sk_buff *skb;
227
	uint32_t buf;
228
	uint16_t len;
229
	uint8_t *skb_data;
230

231
	packet = (REG16_LOAD(BANK_FIFO_PORTS) >> 8) & 0xFF;
232
	if (packet == FIFO_EMPTY) {
233
		return 0;
234
	}
235

236
	REG16_STORE(BANK_POINTER,
237
			RX_FIFO_PACKET | AUTO_INCR | LAN91C111_STATUS_BYTES);
238
	len = (REG16_LOAD(BANK_DATA) & PLEN_MASK) - 10;
239
	/* In original structure, byte count includes headers, so
240
	 * we shrink it to data size */
241

242
	skb = skb_alloc(len + LAN91C111_STATUS_BYTES);
243
	assert(skb);
244
	skb->len = len;
245
	skb->dev = dev_id;
246

247
	skb_data = skb_data_cast_in(skb->data);
248
	assert(skb_data);
249

250
	for (i = 0; i < len >> 2; i++) {
251
		buf = REG32_LOAD(BANK_DATA);
252
		*((uint32_t *)(skb_data + i * 4)) = buf;
253
	}
254

255
	if (len % 4 == 2) {
256
		buf = REG16_LOAD(BANK_DATA);
257
		*((uint16_t *)(skb_data + i * 4)) = buf & 0xFFFF;
258
	}
259

260
	/* Skip 4 bytes CRC */
261
	buf = REG32_LOAD(BANK_DATA);
262
	buf = REG16_LOAD(BANK_DATA);
263

264
	lan91c111_set_cmd(CMD_RX_POP_AND_RELEASE);
265

266
	if (buf & (ODD_CONTROL << 8)) {
267
		skb->len++;
268
		skb_data[skb->len -1] = (uint8_t)(buf & 0xFF);
269
	}
270
	show_packet(skb_data, len, "rx_pack");
271

272
	netif_rx(skb);
273

274
	return 0;
275
}
276

277
static irq_return_t lan91c111_int_handler(unsigned int irq_num, void *dev_id) {
278
	uint8_t int_status;
279
	uint8_t int_mask;
280

281
	ipl_t ipl;
282

283
	ipl = ipl_save();
284
	{
285
		lan91c111_set_bank(2);
286

287
		int_status = REG8_LOAD(BANK_INTERRUPT_STATUS);
288
		int_mask = REG8_LOAD(BANK_INTERRUPT_MASK);
289

290
		int_status &= int_mask;
291

292
		if (int_status & RX_MASK) {
293
			lan91c111_recv_hw(dev_id);
294
		}
295

296
		if (int_status & ALLOC_MASK) {
297
			int_mask &= ~ALLOC_INT;
298
			REG8_STORE(BANK_INTERRUPT_MASK, int_mask);
299
			lan91c111_tx_pend(dev_id);
300
		}
301

302
	}
303
	ipl_restore(ipl);
304

305
	return 0;
306
}
307

308
static int lan91c111_init(void) {
309
	struct net_device *nic;
310
	struct smc_local *smc_local;
311

312
	if (NULL == (nic = etherdev_alloc(sizeof(struct smc_local)))) {
313
		return -ENOMEM;
314
	}
315

316
	irq_attach(LAN91C111_IRQ, lan91c111_int_handler, 0, nic, "lan91c111");
317

318
	smc_local = netdev_priv(nic);
319
	skb_queue_init(&smc_local->pending_queue);
320

321
	nic->drv_ops = &lan91c111_drv_ops;
322

323
	lan91c111_set_bank(1);
324
	REG16_STORE(BANK_CONTROL, 0x0800);
325

326
	return inetdev_register_dev(nic);
327
}
328

329
PERIPH_MEMORY_DEFINE(lan91c111, BANK_BASE_ADDR, 0x10);
330

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

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

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

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