Скачиваний:
25
Добавлен:
03.10.2016
Размер:
326.69 Кб
Скачать

 

 

 

Листинг 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

Соседние файлы в предмете Операционные системы и системное программирование