report6
.pdf
|
|
|
Листинг 7: Определения регистров (res/r8169.c) |
|
|
|||||||||
6 |
#d e f i n e |
TX_BUF_SIZE |
1536 |
/* |
should be |
at l e a s t |
MTU + 14 + 4 |
*/ |
||||||
7 |
#d e f i n e |
TOTAL_TX_BUF_SIZE (TX_BUF_SIZE * NUM_TX_SIZE) |
|
|
||||||||||
8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
/* Size |
of the in−memory |
|
r e c e i v e |
ring . |
*/ |
|
|
|
|
||||
10 |
#d e f i n e |
RX_BUF_LEN_IDX 2 |
|
|
|
/* 0==8K, 1==16K, 2==32K, 3==64K */ |
||||||||
11 |
#d e f i n e RX_BUF_LEN |
|
(8192 << RX_BUF_LEN_IDX) |
|
|
|
|
|||||||
12 |
#d e f i n e |
RX_BUF_PAD |
|
16 |
|
|
/* |
see 11 th |
and |
12 th |
b i t |
of RCR: |
||
|
0x44 */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
#d e f i n e RX_BUF_WRAP_PAD 2048 |
/* |
spare |
padding |
to |
handle |
pkt |
wrap |
||||||
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
#d e f i n e RX_BUF_TOT_LEN |
(RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD) |
||||||||||||
15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
/* 8169 |
r e g i s t e r |
o f f s e t s |
|
*/ |
|
|
|
|
|
|
|
||
17 |
#d e f i n e |
TSD0 |
|
|
0x10 |
|
|
|
|
|
|
|
||
18 |
#d e f i n e |
TSAD0 |
|
|
0x20 |
|
|
|
|
|
|
|
||
19 |
#d e f i n e |
RBSTART |
|
|
0x30 |
|
|
|
|
|
|
|
||
20 |
#d e f i n e |
CR |
|
|
0x37 |
|
|
|
|
|
|
|
||
21 |
#d e f i n e |
CAPR |
|
|
0x38 |
|
|
|
|
|
|
|
||
22 |
#d e f i n e |
IMR |
|
|
0x3c |
|
|
|
|
|
|
|
||
23 |
#d e f i n e |
ISR |
|
|
0x3e |
|
|
|
|
|
|
|
||
24 |
#d e f i n e |
TCR |
|
|
0x40 |
|
|
|
|
|
|
|
||
25 |
#d e f i n e |
RCR |
|
|
0x44 |
|
|
|
|
|
|
|
||
26 |
#d e f i n e |
MPC |
|
|
0x4c |
|
|
|
|
|
|
|
||
27 |
#d e f i n e |
MULINT |
|
|
0x5c |
|
|
|
|
|
|
|
||
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
/* TSD |
r e g i s t e r |
commands |
|
*/ |
|
|
|
|
|
|
|
||
30 |
#d e f i n e |
TxHostOwns |
|
0x2000 |
|
|
|
|
|
|
|
|||
31 |
#d e f i n e |
TxUnderrun |
|
0x4000 |
|
|
|
|
|
|
|
|||
32 |
#d e f i n e |
TxStatOK |
|
0x8000 |
|
|
|
|
|
|
|
|||
33 |
#d e f i n e |
TxOutOfWindow |
0x20000000 |
|
|
|
|
|
|
|||||
34 |
#d e f i n e |
TxAborted |
|
0x40000000 |
|
|
|
|
|
|
||||
35 |
#d e f i n e |
TxCarrierLost |
0x80000000 |
|
|
|
|
|
|
|||||
36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
/* CR r e g i s t e r commands |
*/ |
|
|
|
|
|
|
|
|||||
38 |
#d e f i n e |
RxBufEmpty |
0x01 |
|
|
|
|
|
|
|
|
|
||
39 |
#d e f i n e |
CmdTxEnb |
0x04 |
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21
40 |
#d e f i n e |
CmdRxEnb |
0x08 |
41 |
#d e f i n e |
CmdReset |
0x10 |
42 |
|
|
|
43 |
/* ISR |
Bits */ |
|
44 |
#d e f i n e |
RxOK |
0x01 |
45 |
#d e f i n e |
RxErr |
0x02 |
46 |
#d e f i n e |
TxOK |
0x04 |
47 |
#d e f i n e |
TxErr |
0x08 |
48 |
#d e f i n e |
RxOverFlow |
0x10 |
49 |
#d e f i n e |
RxUnderrun |
0x20 |
50 |
#d e f i n e |
RxFIFOOver |
0x40 |
|
|
|
|
Теперь рассмотрим реализацию функций, работающих с устройством для передачи данных (листинг 8). Ранее эти функции были представлены простыми заглушками.
Листинг 8: Определения регистров (res/r8169.c)
232 s t a t i c i n t rtl8169_open ( s t r u c t net_device *dev )
233{
234i n t r e t v a l ;
235 |
s t r u c t rtl8169_private *tp |
= dev−>priv ; |
|||||
236 |
|
|
|
|
|
|
|
237 |
/* |
get the IRQ |
|
|
|
|
|
238 |
* |
second |
arg i s |
i n t e r r u p t |
handler |
||
239 |
* |
t h i r d |
i s f l a g s , 0 |
means |
no |
IRQ sharing |
|
240 |
*/ |
|
|
|
|
|
|
241 |
r e t v a l = |
request_irq ( dev−>irq , |
rtl8169_interrupt , 0 , dev−>name , |
||||
|
|
dev ) ; |
|
|
|
|
|
242 |
i f |
( r e t v a l ) |
|
|
|
|
|
243 |
|
return |
r e t v a l ; |
|
|
|
|
244 |
|
|
|
|
|
|
|
245 |
/* |
get memory f o r |
Tx |
b u f f e r s |
|
246* memory must be DMAable
247*/
248tp−>tx_bufs = pci_alloc_consistent ( tp−>pci_dev , TOTAL_TX_BUF_SIZE,
249&tp−>tx_bufs_dma ) ;
250tp−>rx_ring = pci_alloc_consistent ( tp−>pci_dev , RX_BUF_TOT_LEN,
251&tp−>rx_ring_dma ) ;
252
22
253 |
i f ( ( ! tp−>tx_bufs ) | | |
( ! tp−>rx_ring ) ) |
254 |
{ |
|
255 |
fr e e_ ir q ( dev−>irq , |
dev ) ; |
256
257i f ( tp−>tx_bufs )
258{
259pci_free_consistent ( tp−>pci_dev , TOTAL_TX_BUF_SIZE, tp−>
tx_bufs ,
260 tp−>tx_bufs_dma ) ;
261tp−>tx_bufs = NULL;
262}
263i f ( tp−>rx_ring )
264{
265pci_free_consistent ( tp−>pci_dev , RX_BUF_TOT_LEN, tp−>rx_ring ,
266 tp−>rx_ring_dma ) ;
267tp−>rx_ring = NULL;
268}
269return −ENOMEM;
270}
271
272tp−>tx_flag = 0 ;
273rtl8169_init_ring ( dev ) ;
274rtl8169_hw_start ( dev ) ;
275 |
|
|
|
|
276 |
return |
0 ; |
|
|
277 |
} |
|
|
|
278 |
|
|
|
|
279 |
s t a t i c void rtl8169_init_ring ( s t r u c t net_device *dev ) |
|||
280 |
{ |
|
|
|
281 |
s t r u c t |
rtl8169_private *tp = |
dev−>priv ; |
|
282 |
i n t i ; |
|
|
|
283 |
|
|
|
|
284 |
tp−>cur_tx = 0 ; |
|
||
285 |
tp−>dirty_tx |
= 0 ; |
|
|
286 |
|
|
|
|
287 |
f o r ( i |
= 0 ; |
i < NUM_TX_DESC; |
i++) |
288 |
tp−>tx_buf [ i ] = &tp−>tx_bufs [ i * TX_BUF_SIZE ] ; |
23
289
290 |
return ; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
292 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
293 |
s t a t i c void rtl8169_hw_start ( s t r u c t |
net_device |
*dev ) |
|
|
||||||||||
294 |
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
295 |
s t r u c t rtl8169_private |
*tp |
= |
dev−>priv ; |
|
|
|
|
|
||||||
296 |
void * ioaddr = tp−>mmio_addr ; |
|
|
|
|
|
|
|
|||||||
297 |
u32 |
i ; |
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
299 |
rtl8169_chip_reset ( ioaddr ) ; |
|
|
|
|
|
|
|
|
||||||
300 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
301 |
/* |
Must enable Tx/Rx bef ore |
s e t t i n g t r a n s f e r |
t h r e s h o l d s ! |
*/ |
||||||||||
302 |
writeb (CmdTxEnb | |
CmdRxEnb, |
ioaddr |
+ CR) ; |
|
|
|
|
|
||||||
303 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
304 |
/* |
tx c o n f i g */ |
|
|
|
|
|
|
|
|
|
|
|
||
305 |
w r i t e l (0 x00000600 , |
ioaddr |
+ TCR) ; |
/* DMA |
burst |
s i z e |
1024 |
*/ |
|||||||
306 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
307 |
/* |
rx c o n f i g */ |
|
|
|
|
|
|
|
|
|
|
|
||
308 |
w r i t e l ( ( ( 1 |
<< 12) |
| (7 |
<< |
8) |
| |
(1 << 7) | |
(1 |
<< |
3) |
| (1 << 2) | (1 |
||||
|
|
<< |
1) ) , |
|
|
|
|
|
|
|
|
|
|
|
|
309 |
|
ioaddr |
+ RCR) ; |
|
|
|
|
|
|
|
|
|
|
|
|
310 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
311 |
/* |
i n i t |
Tx |
b u f f e r |
DMA |
addresses |
*/ |
|
|
|
|
|
|
||
312 |
f o r |
( i |
= 0 ; |
i < NUM_TX_DESC; |
i++) |
|
|
|
|
|
|
||||
313 |
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
314 |
w r i t e l ( tp−>tx_bufs_dma + ( tp−>tx_buf [ i ] |
− tp−>tx_bufs ) , |
|
315ioaddr + TSAD0 + ( i * 4) ) ;
316}
317 |
|
|
318 |
/* |
i n i t RBSTART */ |
319 |
w r i t e l ( tp−>rx_ring_dma , ioaddr + RBSTART) ; |
|
320 |
|
|
321 |
/* |
i n i t i a l i z e missed packet counter */ |
322 |
w r i t e l (0 , ioaddr + MPC) ; |
|
323 |
|
|
324 |
/* |
no early −rx i n t e r r u p t s */ |
24
325 |
writew ( ( readw ( ioaddr |
+ MULINT) |
& 0xF000 ) , |
ioaddr + MULINT) ; |
||||||
326 |
|
|
|
|
|
|
|
|
|
|
327 |
/* |
Enable a l l |
known |
i n t e r r u p t s |
by |
s e t t i n g |
the |
i n t e r r u p t mask . */ |
||
328 |
writew (INT_MASK, |
ioaddr |
+ IMR) ; |
|
|
|
|
|||
329 |
|
|
|
|
|
|
|
|
|
|
330 |
netif_start_queue ( dev ) ; |
|
|
|
|
|
||||
331 |
return ; |
|
|
|
|
|
|
|
|
|
332 |
} |
|
|
|
|
|
|
|
|
|
333 |
|
|
|
|
|
|
|
|
|
|
334 |
s t a t i c void rtl8169_chip_reset ( void |
* ioaddr ) |
|
|
||||||
335 |
{ |
|
|
|
|
|
|
|
|
|
336 |
i n t |
i ; |
|
|
|
|
|
|
|
|
337 |
|
|
|
|
|
|
|
|
|
|
338 |
/* |
Soft r e s e t |
the |
chip . |
*/ |
|
|
|
|
|
339 |
writeb (CmdReset , |
ioaddr |
+ CR) ; |
|
|
|
|
|||
340 |
|
|
|
|
|
|
|
|
|
|
341 |
/* |
Check that |
the |
chip |
has f i n i s h e d the r e s e t . |
*/ |
||||
342 |
f o r |
( i = 1000; |
i > 0 ; i −−) |
|
|
|
|
343{
344b a r r i e r ( ) ;
345i f ( ( readb ( ioaddr + CR) & CmdReset) == 0)
346break ;
347udelay (10) ;
348}
349return ;
350}
Функция rtl8169_open (листинг 8, строка 232) начинается с запроса IRQ, что делается вызовом API request_irq (листинг 8, строка 241). В этой функции регистрируется обработчик прерываний rtl8169_interrupt. Эта функция будет вызываться ядром всякий раз, когда устройство генерирует прерывание. Теперь выделим память, куда будут записываться исходящие пакеты, прежде чем они будут переданы в сеть. Вызов API pci_allocate_consistant возвращает виртуальный адрес ядра (листинг 8, строка 248). Физический адрес возвращается в третьем аргументе, который потом будет использован драйвером. Таким образом выделяется память для всех четырех дескрипторов. Функция rtl8169_init_ring (листинг 8, строка 279) распределяет эту память для четырех дескрипторов.
Теперь рассмотрим функцию rtl8169_hw_start (листинг 8, строка 293), которая делает
25
устройство готовым для передачи (и приёма) пакетов. Сначала перезагружаем устройство для того, чтобы оно было в предсказуемом и известном состоянии (листинг 8, строка 299). Это делается с помощью записи в регистр команд CR (Command Register) значения reset (листинг 8, строка 339), что описано в спецификациях. Дождёмся, пока записанное значение можно будет считать обратно, что означает, что устройство перезагружено. Следующая функция, barrier(), вызывается с тем, чтобы ядро выделило память, требуемую для ввода-выхода, без какой-либо оптимизации (листинг 8, строка 344). Поскольку устройство перезагружено, можно записать в регистр CR значения CmdTxEnb | CmdRxEnb, что означает, что устройство будет передавать и принимать пакеты (листинг 8, строка 302). Затем сконфигурируем регистр TCR (Transmission Configuration Register – конфигурационный регистр передачи) (листинг 8, строка 305). Единственное, что мы установим в регистре TCR, это "Max DMA Burst Size per Tx DMA Burst"(максимальный размер буфера DMA для каждого сохраняемого в DMA пакета). Все остальные значения оставим установленными по умолчанию (подробности в спецификациях). Теперь запишем DMA адрес всех четырех дескрипторов в регистры TSAD (Transmission Start Address Descriptor
– дескриптор начального адреса передачи) (листинг 8, строка 315). Остальные строки пока останутся без комментариев. Они потребуется для передачи.
Далее включаем прерывания, сделав для этого запись в регистр IMR (Interrupt Mask Register – регистр маски прерывания) (листинг 8, строка 328). Этот регистр позволит задать, какие прерывания будет генерировать устройство. Наконец, вызываем netif_start_queue (листинг 8, строка 330) с тем, чтобы сообщить ядру, что устройство готово. Осталось лишь реализовать функцию rtl8169_interrupt. Устройство уже готово посылать пакеты, реализация этой функции представлена ниже (листинг 9).
|
|
|
Листинг 9: Функция отправки пакетов (res/r8169.c) |
|||
352 |
s t a t i c i n t |
rtl8169_start_xmit ( s t r u c t sk_buff |
*skb , |
s t r u c t net_device |
||
|
*dev ) |
|
|
|
|
|
353 |
{ |
|
|
|
|
|
354 |
s t r u c t rtl8169_private |
*tp = dev−>priv ; |
|
|
||
355 |
void * ioaddr |
= tp−>mmio_addr ; |
|
|
||
356 |
unsigned |
i n t |
entry = tp−>cur_tx ; |
|
|
|
357 |
unsigned |
i n t |
len = skb−>len ; |
|
|
|
358 |
#d e f i n e ETH_MIN_LEN 60 |
/* minimum Ethernet |
frame |
s i z e */ |
359i f ( len < TX_BUF_SIZE)
360{
361i f ( len < ETH_MIN_LEN)
362 |
memset ( tp−>tx_buf [ entry ] , 0 , ETH_MIN_LEN) ; |
26
363 |
skb_copy_and_csum_dev( skb , tp−>tx_buf [ entry ] ) ; |
364dev_kfree_skb ( skb ) ;
365}
366e l s e
367{
368dev_kfree_skb ( skb ) ;
369 |
return 0 ; |
|
|
370 |
} |
|
|
371 |
w r i t e l ( tp−>tx_flag | |
max( len , |
( unsigned i n t ) ETH_MIN_LEN) , |
372 |
ioaddr + TSD0 + |
( entry * |
s i z e o f ( u32 ) ) ) ; |
373entry++;
374tp−>cur_tx = entry % NUM_TX_DESC;
375
376i f ( tp−>cur_tx == tp−>dirty_tx )
377{
378netif_stop_queue ( dev ) ;
379}
380 |
return 0 ; |
381}
Функция rtl8169_start_xmit (листинг 9, строка 352) крайне проста: сначала она ищет имеющийся дескриптор передачи, а затем проверяет, чтобы размер пакета был, по меньшей мере, 60 байтов (поскольку размер пакетов Ethernet не может быть меньше 60 байтов)(листинг 9, строка 359). Как только это будет сделано, будет вызвана функция skb_copy_and_csum_dev (листинг 9, строка 363), которая скопирует содержимое пакетов в имеющуюся память DMA. Следующая функция writel (листинг 9, строка 371) информирует устройство о длине пакета. После этого пакеты передаются в сеть. Далее определяем имеющиеся в наличии следующие дескрипторы передачи и, если он будет равен дескриптору, для которого передача еще не завершена (листинг 9, строка 376), то остановим устройство; в противном случае просто выйдем из функции.
Теперь устройство готово отсылать пакеты. Для приёма пакетов, вернёмся к листингу 8. В строке 308 производится конфигурирование сетевой карты для приёма сообщений (подробности есть в спецификации[4]):
∙Бит 1 – Принимаются пакеты с проверкой физического адреса (адреса MAC).
∙Бит 2 – Принимаются многоадресные пакеты (посылаемые на несколько адресов)
∙Бит 3 – Принимаются широковещательные пакеты (посылаемые на все адреса)
27
∙Бит 7 – WRAP. Когда установлен в 1, то RTL8169 будет перемещать оставшуюся часть пакетных данных в память, которая следует непосредственно за концом премного буфера.
∙Биты 8-10 – Максимальный размер буфера DMA для каждого сохраняемого в DMA пакета. Значение 111 соответствует отсутствию ограничений.
∙Биты 11-12 – Длина буфера приема. Устанавливаем это значение равным 10, что означает 32K+16 байтов.
Кроме того, стоит отметить конфигурирование регистра RBSTART (листинг 8, строка 319). В этом регистре содержится стартовый адрес приемного буфера. Далее обнуляем регистр MPC (Missed Packet Counter – счетчик ошибочных пакетов) (листинг 8, строка 322) и конфигурируем устройство так, чтобы не генерировались ранние прерывания (листинг 8, строка 325).
Последний важный момент, который нужно обсудить – обработчик прерываний устройства. Этот обработчик прерываний ответственен за прием пакетов, а также за обновление необходимой статистики. Ниже (листинг 10) приведен его исходный код.
|
|
|
|
|
Листинг 10: Обработчик прерываний (res/r8169.c) |
|
|
|||||||||||
383 |
s t a t i c |
void |
rtl8169_interrupt ( i n t |
irq , |
void |
*dev_instance , s t r u c t |
||||||||||||
|
pt_regs |
* regs ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
384 |
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
385 |
s t r u c t net_device |
*dev |
= ( s t r u c t |
net_device *) |
dev_instance ; |
|
||||||||||||
386 |
s t r u c t rtl8169_private |
*tp = dev−>priv ; |
|
|
|
|
||||||||||||
387 |
void |
* ioaddr = tp−>mmio_addr ; |
|
|
|
|
|
|
||||||||||
388 |
unsigned |
short |
i s r |
= |
readw ( ioaddr + ISR ) ; |
|
|
|
|
|||||||||
389 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
390 |
/* c l e a r |
a l l i n t e r r u p t . |
|
|
|
|
|
|
|
|
||||||||
391 |
* |
Specs |
says reading |
|
ISR |
c l e a r s |
a l l |
i n t e r r u p t s and |
writing |
|
||||||||
392 |
* |
has no |
e f f e c t . |
But |
|
t h i s |
does |
not seem |
to be |
case . |
I keep |
on |
||||||
393 |
* g e t t i n g |
i n t e r r u p t |
u n l e s s I f o r c i b l y c l e a r s |
a l l i n t e r r u p t |
:−( |
|||||||||||||
394 |
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
395 |
writew (0 x f f f f , |
ioaddr |
+ |
ISR ) ; |
|
|
|
|
|
|
||||||||
396 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
397 |
i f |
( ( i s r |
& TxOK) |
| | |
( i s r |
& TxErr ) ) |
|
|
|
|
|
|||||||
398 |
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
399 |
|
while |
( ( tp−>dirty_tx |
!= |
tp−>cur_tx ) |
| | |
netif_queue_stopped ( dev ) ) |
|||||||||||
400 |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
|
unsigned i n t |
t x s t a t u s = |
r e a d l ( |
|
||||
|
|
ioaddr + TSD0 + |
tp−>dirty_tx |
* s i z e o f ( i n t ) ) ; |
||||
|
i f |
( ! ( t x s t a t u s |
& (TxStatOK | TxAborted | TxUnderrun ) ) ) |
|||||
|
break ; /* |
yet |
not |
transmitted */ |
||||
|
i f |
( t x s t a t u s |
& TxStatOK) |
|
||||
|
{ |
|
|
|
|
|
|
|
|
LOG_MSG( "Transmit OK |
i n t e r r u p t \n" ) ; |
||||||
|
tp−>s t a t s . tx_bytes |
+= |
( t x s t a t u s |
& 0 x 1 f f f ) ; |
||||
|
tp−>s t a t s . tx_packets++; |
|
||||||
|
} |
|
|
|
|
|
|
|
|
e l s e |
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
LOG_MSG( "Transmit |
Error i n t e r r u p t \n" ) ; |
||||||
|
tp−>s t a t s . tx_errors++; |
|
||||||
|
} |
|
|
|
|
|
|
|
|
tp−>dirty_tx++; |
|
|
|
||||
|
tp−>dirty_tx = tp−>dirty_tx % NUM_TX_DESC; |
|||||||
|
i f |
( ( tp−>dirty_tx == tp−>cur_tx ) |
& netif_queue_stopped ( dev ) ) |
|||||
|
{ |
|
|
|
|
|
|
|
|
LOG_MSG( "waking up queue\n" ) ; |
|
||||||
|
netif_wake_queue ( dev ) ; |
|
||||||
|
} |
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
i f |
( i s r |
& |
RxErr ) |
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
/* TODO: |
Need |
d e t a i l e d |
a n a l y s i s of |
e r r o r s t a t u s */ |
|||
|
LOG_MSG( " r e c e i v e |
e r r i n t e r r u p t \n" ) ; |
|
|||||
} |
tp−>s t a t s . rx_errors++; |
|
|
|
||||
|
|
|
|
|
|
|
|
|
i f |
( i s r |
& RxOK) |
|
|
|
|
|
29
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
{
LOG_MSG( " r e c e i v e |
i n t e r r u p t r e c e i v e d \n" ) ; |
while ( ( readb ( ioaddr + CR) & RxBufEmpty) == 0) |
|
{ |
|
unsigned i n t rx_status ; |
|
unsigned short |
rx_size ; |
unsigned short |
pkt_size ; |
s t r u c t sk_buff |
*skb ; |
i f |
( tp−>cur_rx > RX_BUF_LEN) |
|
|
|
|
||||
|
tp−>cur_rx = tp−>cur_rx % RX_BUF_LEN; |
|
|
|
|||||
/* TODO: need to |
convert |
rx_status from |
l i t t l e |
to host |
endian |
||||
* XXX: My CPU i s |
l i t t l e |
endian |
only :−) |
|
|
|
|||
*/ |
|
|
|
|
|
|
|
|
|
rx_status = *( unsigned |
i n t *) ( tp−>rx_ring + tp−>cur_rx ) ; |
||||||||
rx_size = rx_status >> 16; |
|
|
|
|
|||||
/* |
f i r s t two |
bytes are |
r e c e i v e |
s t a t u s r e g i s t e r |
|
|
|||
* |
and next |
two bytes |
are |
frame |
length |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
pkt_size = rx_size − 4 ; |
|
|
|
|
|
||||
/* hand over packet to system */ |
|
|
|
||||||
skb = dev_alloc_skb ( pkt_size + 2) ; |
|
|
|
||||||
i f |
( skb ) |
|
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
|
skb−>dev = dev ; |
|
|
|
|
|
|
|
|
|
skb_reserve ( skb , 2) ; /* |
16 byte a l i g n |
the IP |
f i e l d s |
*/ |
||||
|
eth_copy_and_sum( skb , tp−>rx_ring + tp−>cur_rx + 4 , |
pkt_size |
|||||||
|
, |
|
|
|
|
|
|
|
|
|
0) ; |
|
|
|
|
|
|
|
|
|
skb_put ( skb , pkt_size ) ; |
|
|
|
|
|
|||
|
skb−>p rot o co l = |
eth_type_trans ( skb , dev ) ; |
|
|
|||||
|
netif_rx ( skb ) ; |
|
|
|
|
|
|
|
30