1 /*
2 * Copyright (C) 2012 Adrian Jamróz <adrian.jamroz@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdint.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <byteswap.h>
27 #include <ipxe/netdevice.h>
28 #include <ipxe/ethernet.h>
29 #include <ipxe/if_ether.h>
30 #include <ipxe/iobuf.h>
31 #include <ipxe/malloc.h>
32 #include <ipxe/pci.h>
33 #include <ipxe/mii.h>
34 #include "velocity.h"
35
36 #define velocity_setbit(_reg, _mask) writeb ( readb ( _reg ) | _mask, _reg )
37 #define virt_to_le32bus(x) ( cpu_to_le32 ( virt_to_bus ( x ) ) )
38
39 /** @file
40 *
41 * VIA Velocity network driver
42 *
43 */
44
45 /******************************************************************************
46 *
47 * MII interface
48 *
49 ******************************************************************************
50 */
51
52 /**
53 * Stop MII auto-polling
54 *
55 * @v vlc Velocity device
56 * @ret rc Return status code
57 */
velocity_autopoll_stop(struct velocity_nic * vlc)58 static int velocity_autopoll_stop ( struct velocity_nic *vlc ) {
59 int timeout = VELOCITY_TIMEOUT_US;
60
61 /* Disable MII auto polling */
62 writeb ( 0, vlc->regs + VELOCITY_MIICR );
63
64 /* Wait for disabling to take effect */
65 while ( timeout-- ) {
66 udelay ( 1 );
67 if ( readb ( vlc->regs + VELOCITY_MIISR ) &
68 VELOCITY_MIISR_IDLE )
69 return 0;
70 }
71
72 DBGC ( vlc, "MII autopoll stop timeout\n" );
73 return -ETIMEDOUT;
74 }
75
76 /**
77 * Start MII auto-polling
78 *
79 * @v vlc Velocity device
80 * @ret rc Return status code
81 */
velocity_autopoll_start(struct velocity_nic * vlc)82 static int velocity_autopoll_start ( struct velocity_nic *vlc ) {
83 int timeout = VELOCITY_TIMEOUT_US;
84
85 /* Enable MII auto polling */
86 writeb ( VELOCITY_MIICR_MAUTO, vlc->regs + VELOCITY_MIICR );
87
88 /* Wait for enabling to take effect */
89 while ( timeout-- ) {
90 udelay ( 1 );
91 if ( ( readb ( vlc->regs + VELOCITY_MIISR ) &
92 VELOCITY_MIISR_IDLE ) == 0 )
93 return 0;
94 }
95
96 DBGC ( vlc, "MII autopoll start timeout\n" );
97 return -ETIMEDOUT;
98 }
99
100 /**
101 * Read from MII register
102 *
103 * @v mdio MII interface
104 * @v phy PHY address
105 * @v reg Register address
106 * @ret value Data read, or negative error
107 */
velocity_mii_read(struct mii_interface * mdio,unsigned int phy __unused,unsigned int reg)108 static int velocity_mii_read ( struct mii_interface *mdio,
109 unsigned int phy __unused, unsigned int reg ) {
110 struct velocity_nic *vlc =
111 container_of ( mdio, struct velocity_nic, mdio );
112 int timeout = VELOCITY_TIMEOUT_US;
113 int result;
114
115 DBGC2 ( vlc, "VELOCITY %p MII read reg %d\n", vlc, reg );
116
117 /* Disable autopolling before we can access MII */
118 velocity_autopoll_stop ( vlc );
119
120 /* Send read command and address */
121 writeb ( reg, vlc->regs + VELOCITY_MIIADDR );
122 velocity_setbit ( vlc->regs + VELOCITY_MIICR, VELOCITY_MIICR_RCMD );
123
124 /* Wait for read to complete */
125 while ( timeout-- ) {
126 udelay ( 1 );
127 if ( ( readb ( vlc->regs + VELOCITY_MIICR ) &
128 VELOCITY_MIICR_RCMD ) == 0 ) {
129 result = readw ( vlc->regs + VELOCITY_MIIDATA );
130 velocity_autopoll_start ( vlc );
131 return result;
132 }
133 }
134
135 /* Restart autopolling */
136 velocity_autopoll_start ( vlc );
137
138 DBGC ( vlc, "MII read timeout\n" );
139 return -ETIMEDOUT;
140 }
141
142 /**
143 * Write to MII register
144 *
145 * @v mdio MII interface
146 * @v phy PHY address
147 * @v reg Register address
148 * @v data Data to write
149 * @ret rc Return status code
150 */
velocity_mii_write(struct mii_interface * mdio,unsigned int phy __unused,unsigned int reg,unsigned int data)151 static int velocity_mii_write ( struct mii_interface *mdio,
152 unsigned int phy __unused, unsigned int reg,
153 unsigned int data) {
154 struct velocity_nic *vlc =
155 container_of ( mdio, struct velocity_nic, mdio );
156 int timeout = VELOCITY_TIMEOUT_US;
157
158 DBGC2 ( vlc, "VELOCITY %p MII write reg %d data 0x%04x\n",
159 vlc, reg, data );
160
161 /* Disable autopolling before we can access MII */
162 velocity_autopoll_stop ( vlc );
163
164 /* Send write command, data and destination register */
165 writeb ( reg, vlc->regs + VELOCITY_MIIADDR );
166 writew ( data, vlc->regs + VELOCITY_MIIDATA );
167 velocity_setbit ( vlc->regs + VELOCITY_MIICR, VELOCITY_MIICR_WCMD );
168
169 /* Wait for write to complete */
170 while ( timeout-- ) {
171 udelay ( 1 );
172 if ( ( readb ( vlc->regs + VELOCITY_MIICR ) &
173 VELOCITY_MIICR_WCMD ) == 0 ) {
174 velocity_autopoll_start ( vlc );
175 return 0;
176 }
177 }
178
179 /* Restart autopolling */
180 velocity_autopoll_start ( vlc );
181
182 DBGC ( vlc, "MII write timeout\n" );
183 return -ETIMEDOUT;
184 }
185
186 /** Velocity MII operations */
187 static struct mii_operations velocity_mii_operations = {
188 .read = velocity_mii_read,
189 .write = velocity_mii_write,
190 };
191
192 /**
193 * Set Link speed
194 *
195 * @v vlc Velocity device
196 */
velocity_set_link(struct velocity_nic * vlc)197 static void velocity_set_link ( struct velocity_nic *vlc ) {
198 int tmp;
199
200 /* Advertise 1000MBit */
201 tmp = mii_read ( &vlc->mii, MII_CTRL1000 );
202 tmp |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
203 mii_write ( &vlc->mii, MII_CTRL1000, tmp );
204
205 /* Enable GBit operation in MII Control Register */
206 tmp = mii_read ( &vlc->mii, MII_BMCR );
207 tmp |= BMCR_SPEED1000;
208 mii_write ( &vlc->mii, MII_BMCR, tmp );
209 }
210
211 /******************************************************************************
212 *
213 * Device reset
214 *
215 ******************************************************************************
216 */
217
218 /**
219 * Reload eeprom contents
220 *
221 * @v vlc Velocity device
222 */
velocity_reload_eeprom(struct velocity_nic * vlc)223 static int velocity_reload_eeprom ( struct velocity_nic *vlc ) {
224 int timeout = VELOCITY_TIMEOUT_US;
225
226 /* Initiate reload */
227 velocity_setbit ( vlc->regs + VELOCITY_EECSR, VELOCITY_EECSR_RELOAD );
228
229 /* Wait for reload to complete */
230 while ( timeout-- ) {
231 udelay ( 1 );
232 if ( ( readb ( vlc->regs + VELOCITY_EECSR ) &
233 VELOCITY_EECSR_RELOAD ) == 0 )
234 return 0;
235 }
236
237 DBGC ( vlc, "VELOCITY %p EEPROM reload timeout\n", vlc );
238 return -ETIMEDOUT;
239 }
240
241 /**
242 * Reset hardware
243 *
244 * @v vlc Velocity device
245 * @ret rc Return status code
246 */
velocity_reset(struct velocity_nic * vlc)247 static int velocity_reset ( struct velocity_nic *vlc ) {
248 int timeout = VELOCITY_TIMEOUT_US;
249 uint8_t tmp;
250
251 DBGC ( vlc, "VELOCITY %p reset\n", vlc );
252
253 /* clear sticky Power state bits */
254 tmp = readb ( vlc->regs + VELOCITY_STICKY );
255 tmp &= ~( VELOCITY_STICKY_DS0 | VELOCITY_STICKY_DS1 );
256 writeb ( tmp, vlc->regs + VELOCITY_STICKY );
257
258 /* clear PACPI, which might have been enabled by the EEPROM reload */
259 tmp = readb ( vlc->regs + VELOCITY_CFGA );
260 tmp &= ~VELOCITY_CFGA_PACPI;
261 writeb ( tmp, vlc->regs + VELOCITY_CFGA );
262
263 velocity_setbit ( vlc->regs + VELOCITY_CRS1, VELOCITY_CR1_SFRST );
264
265 /* Wait for reset to complete */
266 while ( timeout-- ) {
267 udelay ( 1 );
268 if ( ( readb ( vlc->regs + VELOCITY_CRS1 ) &
269 VELOCITY_CR1_SFRST ) == 0 )
270 return 0;
271 }
272
273 return -EINVAL;
274 }
275
276 /******************************************************************************
277 *
278 * Link state
279 *
280 ******************************************************************************
281 */
282
283 /**
284 * Check link state
285 *
286 * @v netdev Network device
287 */
velocity_check_link(struct net_device * netdev)288 static void velocity_check_link ( struct net_device *netdev ) {
289 struct velocity_nic *vlc = netdev->priv;
290
291 if ( readb ( vlc->regs + VELOCITY_PHYSTS0 ) & VELOCITY_PHYSTS0_LINK ) {
292 netdev_link_up ( netdev );
293 DBGC ( vlc, "VELOCITY %p link up\n", vlc );
294 } else {
295 netdev_link_down ( netdev );
296 DBGC ( vlc, "VELOCITY %p link down\n", vlc );
297 }
298
299 /* The card disables auto-poll after a link change */
300 velocity_autopoll_start ( vlc );
301 }
302
303 /******************************************************************************
304 *
305 * Network device interface
306 *
307 ******************************************************************************
308 */
309
310 /**
311 * Allocate descriptor rings
312 *
313 * @v vlc Velocity device
314 * @ret rc Return status code
315 */
velocity_alloc_rings(struct velocity_nic * vlc)316 static int velocity_alloc_rings ( struct velocity_nic *vlc ) {
317 int rc = 0;
318
319 /* Allocate RX descriptor ring */
320 vlc->rx_prod = 0;
321 vlc->rx_cons = 0;
322 vlc->rx_commit = 0;
323 vlc->rx_ring = malloc_dma ( VELOCITY_RXDESC_SIZE, VELOCITY_RING_ALIGN );
324 if ( ! vlc->rx_ring )
325 return -ENOMEM;
326
327 memset ( vlc->rx_ring, 0, VELOCITY_RXDESC_SIZE );
328
329 DBGC2 ( vlc, "VELOCITY %p RX ring start address: %p(phys: %#08lx)\n",
330 vlc, vlc->rx_ring, virt_to_bus ( vlc->rx_ring ) );
331
332 /* Allocate TX descriptor ring */
333 vlc->tx_prod = 0;
334 vlc->tx_cons = 0;
335 vlc->tx_ring = malloc_dma ( VELOCITY_TXDESC_SIZE, VELOCITY_RING_ALIGN );
336 if ( ! vlc->tx_ring ) {
337 rc = -ENOMEM;
338 goto err_tx_alloc;
339 }
340
341 memset ( vlc->tx_ring, 0, VELOCITY_TXDESC_SIZE );
342
343 /* Send RX ring to the card */
344 writel ( virt_to_bus ( vlc->rx_ring ),
345 vlc->regs + VELOCITY_RXDESC_ADDR_LO );
346 writew ( VELOCITY_RXDESC_NUM - 1, vlc->regs + VELOCITY_RXDESCNUM );
347
348 /* Send TX ring to the card */
349 writel ( virt_to_bus ( vlc->tx_ring ),
350 vlc->regs + VELOCITY_TXDESC_ADDR_LO0 );
351 writew ( VELOCITY_TXDESC_NUM - 1, vlc->regs + VELOCITY_TXDESCNUM );
352
353 DBGC2 ( vlc, "VELOCITY %p TX ring start address: %p(phys: %#08lx)\n",
354 vlc, vlc->tx_ring, virt_to_bus ( vlc->tx_ring ) );
355
356 return 0;
357
358 err_tx_alloc:
359 free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE );
360 return rc;
361 }
362
363 /**
364 * Refill receive descriptor ring
365 *
366 * @v vlc Velocity device
367 */
velocity_refill_rx(struct velocity_nic * vlc)368 static void velocity_refill_rx ( struct velocity_nic *vlc ) {
369 struct velocity_rx_descriptor *desc;
370 struct io_buffer *iobuf;
371 int rx_idx, i = 0;
372
373 /* Check for new packets */
374 while ( ( vlc->rx_prod - vlc->rx_cons ) < VELOCITY_RXDESC_NUM ) {
375 iobuf = alloc_iob ( VELOCITY_RX_MAX_LEN );
376
377 /* Memory pressure: try again next poll */
378 if ( ! iobuf )
379 break;
380
381 rx_idx = ( vlc->rx_prod++ % VELOCITY_RXDESC_NUM );
382 desc = &vlc->rx_ring[rx_idx];
383
384 /* Set descrptor fields */
385 desc->des1 = 0;
386 desc->addr = virt_to_le32bus ( iobuf-> data );
387 desc->des2 = cpu_to_le32 (
388 VELOCITY_DES2_SIZE ( VELOCITY_RX_MAX_LEN - 1 ) |
389 VELOCITY_DES2_IC );
390
391 vlc->rx_buffs[rx_idx] = iobuf;
392 i++;
393
394 /* Return RX descriptors in blocks of 4 (hw requirement) */
395 if ( rx_idx % 4 == 3 ) {
396 int j;
397 for (j = 0; j < 4; j++) {
398 desc = &vlc->rx_ring[rx_idx - j];
399 desc->des0 = cpu_to_le32 ( VELOCITY_DES0_OWN );
400 }
401 vlc->rx_commit += 4;
402 }
403 }
404
405 wmb();
406
407 if ( vlc->rx_commit ) {
408 writew ( vlc->rx_commit,
409 vlc->regs + VELOCITY_RXDESC_RESIDUECNT );
410 vlc->rx_commit = 0;
411 }
412
413 if ( i > 0 )
414 DBGC2 ( vlc, "VELOCITY %p refilled %d RX descriptors\n",
415 vlc, i );
416 }
417
418 /**
419 * Open network device
420 *
421 * @v netdev Network device
422 * @ret rc Return status code
423 */
velocity_open(struct net_device * netdev)424 static int velocity_open ( struct net_device *netdev ) {
425 struct velocity_nic *vlc = netdev->priv;
426 int rc;
427
428 DBGC ( vlc, "VELOCITY %p open\n", vlc );
429 DBGC ( vlc, "VELOCITY %p regs at: %p\n", vlc, vlc->regs );
430
431 /* Allocate descriptor rings */
432 if ( ( rc = velocity_alloc_rings ( vlc ) ) != 0 )
433 return rc;
434
435 velocity_refill_rx ( vlc );
436
437 /* Enable TX/RX queue */
438 writew ( VELOCITY_TXQCSRS_RUN0, vlc->regs + VELOCITY_TXQCSRS );
439 writew ( VELOCITY_RXQCSR_RUN | VELOCITY_RXQCSR_WAK,
440 vlc->regs + VELOCITY_RXQCSRS );
441
442 /* Enable interrupts */
443 writeb ( 0xff, vlc->regs + VELOCITY_IMR0 );
444 writeb ( 0xff, vlc->regs + VELOCITY_IMR1 );
445
446 /* Start MAC */
447 writeb ( VELOCITY_CR0_STOP, vlc->regs + VELOCITY_CRC0 );
448 writeb ( VELOCITY_CR1_DPOLL, vlc->regs + VELOCITY_CRC0 );
449 writeb ( VELOCITY_CR0_START | VELOCITY_CR0_TXON | VELOCITY_CR0_RXON,
450 vlc->regs + VELOCITY_CRS0 );
451
452 /* Receive all packets */
453 writeb ( 0xff, vlc->regs + VELOCITY_RCR );
454
455 /* Set initial link state */
456 velocity_check_link ( netdev );
457
458 velocity_autopoll_start ( vlc );
459
460 DBGC2 ( vlc, "VELOCITY %p CR3 %02x\n",
461 vlc, readb ( vlc->regs + 0x0B ) );
462
463 return 0;
464 }
465
466 /**
467 * Close network device
468 *
469 * @v netdev Network device
470 */
velocity_close(struct net_device * netdev)471 static void velocity_close ( struct net_device *netdev ) {
472 struct velocity_nic *vlc = netdev->priv;
473 int i;
474
475 /* Stop NIC */
476 writeb ( VELOCITY_CR0_TXON | VELOCITY_CR0_RXON,
477 vlc->regs + VELOCITY_CRC0 );
478 writeb ( VELOCITY_CR0_STOP, vlc->regs + VELOCITY_CRS0 );
479
480 /* Clear RX ring information */
481 writel ( 0, vlc->regs + VELOCITY_RXDESC_ADDR_LO );
482 writew ( 0, vlc->regs + VELOCITY_RXDESCNUM );
483
484 /* Destroy RX ring */
485 free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE );
486 vlc->rx_ring = NULL;
487 vlc->rx_prod = 0;
488 vlc->rx_cons = 0;
489
490 /* Discard receive buffers */
491 for ( i = 0 ; i < VELOCITY_RXDESC_NUM ; i++ ) {
492 if ( vlc->rx_buffs[i] )
493 free_iob ( vlc->rx_buffs[i] );
494 vlc->rx_buffs[i] = NULL;
495 }
496
497 /* Clear TX ring information */
498 writel ( 0, vlc->regs + VELOCITY_TXDESC_ADDR_LO0 );
499 writew ( 0, vlc->regs + VELOCITY_TXDESCNUM );
500
501 /* Destroy TX ring */
502 free_dma ( vlc->tx_ring, VELOCITY_TXDESC_SIZE );
503 vlc->tx_ring = NULL;
504 vlc->tx_prod = 0;
505 vlc->tx_cons = 0;
506 }
507
508 /**
509 * Transmit packet
510 *
511 * @v netdev Network device
512 * @v iobuf I/O buffer
513 * @ret rc Return status code
514 */
velocity_transmit(struct net_device * netdev,struct io_buffer * iobuf)515 static int velocity_transmit ( struct net_device *netdev,
516 struct io_buffer *iobuf ) {
517 struct velocity_nic *vlc = netdev->priv;
518 struct velocity_tx_descriptor *desc;
519 unsigned int tx_idx;
520
521 /* Pad packet to minimum length */
522 iob_pad ( iobuf, ETH_ZLEN );
523
524 tx_idx = ( vlc->tx_prod++ % VELOCITY_TXDESC_NUM );
525 desc = &vlc->tx_ring[tx_idx];
526
527 /* Set packet size and transfer ownership to NIC */
528 desc->des0 = cpu_to_le32 ( VELOCITY_DES0_OWN |
529 VELOCITY_DES2_SIZE ( iob_len ( iobuf ) ) );
530 /* Data in first desc fragment, only desc for packet, generate INT */
531 desc->des1 = cpu_to_le32 ( VELOCITY_DES1_FRAG ( 1 ) |
532 VELOCITY_DES1_TCPLS |
533 VELOCITY_DES1_INTR );
534
535 desc->frags[0].addr = virt_to_le32bus ( iobuf->data );
536 desc->frags[0].des2 = cpu_to_le32 (
537 VELOCITY_DES2_SIZE ( iob_len ( iobuf ) ) );
538
539 wmb();
540
541 /* Initiate TX */
542 velocity_setbit ( vlc->regs + VELOCITY_TXQCSRS, VELOCITY_TXQCSRS_WAK0 );
543
544 DBGC2 ( vlc, "VELOCITY %p tx_prod=%d desc=%p iobuf=%p len=%zd\n",
545 vlc, tx_idx, desc, iobuf->data, iob_len ( iobuf ) );
546
547 return 0;
548 }
549
550 /**
551 * Poll for received packets.
552 *
553 * @v vlc Velocity device
554 */
velocity_poll_rx(struct velocity_nic * vlc)555 static void velocity_poll_rx ( struct velocity_nic *vlc ) {
556 struct velocity_rx_descriptor *desc;
557 struct io_buffer *iobuf;
558 int rx_idx;
559 size_t len;
560 uint32_t des0;
561
562 /* Check for packets */
563 while ( vlc->rx_cons != vlc->rx_prod ) {
564 rx_idx = ( vlc->rx_cons % VELOCITY_RXDESC_NUM );
565 desc = &vlc->rx_ring[rx_idx];
566
567 des0 = cpu_to_le32 ( desc->des0 );
568
569 /* Return if descriptor still in use */
570 if ( des0 & VELOCITY_DES0_OWN )
571 return;
572
573 iobuf = vlc->rx_buffs[rx_idx];
574
575 /* Get length, strip CRC */
576 len = VELOCITY_DES0_RMBC ( des0 ) - 4;
577 iob_put ( iobuf, len );
578
579 DBGC2 ( vlc, "VELOCITY %p got packet on idx=%d (prod=%d), len %zd\n",
580 vlc, rx_idx, vlc->rx_prod % VELOCITY_RXDESC_NUM, len );
581
582 if ( des0 & VELOCITY_DES0_RX_ERR ) {
583 /* Report receive error */
584 netdev_rx_err ( vlc->netdev, iobuf, -EINVAL );
585 DBGC ( vlc, "VELOCITY %p receive error, status: %02x\n",
586 vlc, des0 );
587 } else if ( des0 & VELOCITY_DES0_RXOK ) {
588 /* Report receive success */
589 netdev_rx( vlc->netdev, iobuf );
590 } else {
591 /* Card indicated neither success nor failure
592 * Technically this shouldn't happen, but we saw it
593 * in debugging once. */
594 DBGC ( vlc, "VELOCITY %p RX neither ERR nor OK: %04x\n",
595 vlc, des0 );
596 DBGC ( vlc, "packet len: %zd\n", len );
597 DBGC_HD ( vlc, iobuf->data, 64 );
598
599 /* we don't know what it is, treat is as an error */
600 netdev_rx_err ( vlc->netdev, iobuf, -EINVAL );
601 }
602
603 vlc->rx_cons++;
604 }
605 }
606
607 /**
608 * Poll for completed packets.
609 *
610 * @v vlc Velocity device
611 */
velocity_poll_tx(struct velocity_nic * vlc)612 static void velocity_poll_tx ( struct velocity_nic *vlc ) {
613 struct velocity_tx_descriptor *desc;
614 int tx_idx;
615
616 /* Check for packets */
617 while ( vlc->tx_cons != vlc->tx_prod ) {
618 tx_idx = ( vlc->tx_cons % VELOCITY_TXDESC_NUM );
619 desc = &vlc->tx_ring[tx_idx];
620
621 /* Return if descriptor still in use */
622 if ( le32_to_cpu ( desc->des0 ) & VELOCITY_DES0_OWN )
623 return;
624
625 /* Report errors */
626 if ( le32_to_cpu ( desc->des0 ) & VELOCITY_DES0_TERR ) {
627 netdev_tx_complete_next_err ( vlc->netdev, -EINVAL );
628 return;
629 }
630
631 netdev_tx_complete_next ( vlc->netdev );
632
633 DBGC2 ( vlc, "VELOCITY %p poll_tx cons=%d prod=%d tsr=%04x\n",
634 vlc, tx_idx, vlc->tx_prod % VELOCITY_TXDESC_NUM,
635 ( desc->des0 & 0xffff ) );
636 vlc->tx_cons++;
637 }
638 }
639
640 /**
641 * Poll for completed and received packets
642 *
643 * @v netdev Network device
644 */
velocity_poll(struct net_device * netdev)645 static void velocity_poll ( struct net_device *netdev ) {
646 struct velocity_nic *vlc = netdev->priv;
647 uint8_t isr1;
648
649 isr1 = readb ( vlc->regs + VELOCITY_ISR1 );
650
651 /* ACK interrupts */
652 writew ( 0xFFFF, vlc->regs + VELOCITY_ISR0 );
653
654 /* Check for competed packets */
655 velocity_poll_rx ( vlc );
656 velocity_poll_tx ( vlc );
657
658 if ( isr1 & VELOCITY_ISR1_SRCI ) {
659 /* Update linkstate */
660 DBGC2 ( vlc, "VELOCITY %p link status interrupt\n", vlc );
661 velocity_check_link ( netdev );
662 }
663
664 velocity_refill_rx ( vlc );
665
666 /* deal with potential RX stall caused by RX ring underrun */
667 writew ( VELOCITY_RXQCSR_RUN | VELOCITY_RXQCSR_WAK,
668 vlc->regs + VELOCITY_RXQCSRS );
669 }
670
671 /**
672 * Enable or disable interrupts
673 *
674 * @v netdev Network device
675 * @v enable Interrupts should be enabled
676 */
velocity_irq(struct net_device * netdev,int enable)677 static void velocity_irq ( struct net_device *netdev, int enable ) {
678 struct velocity_nic *vlc = netdev->priv;
679
680 DBGC ( vlc, "VELOCITY %p interrupts %s\n", vlc,
681 enable ? "enable" : "disable" );
682
683 if (enable) {
684 /* Enable interrupts */
685 writeb ( VELOCITY_CR3_GINTMSK1, vlc->regs + VELOCITY_CRS3 );
686 } else {
687 /* Disable interrupts */
688 writeb ( VELOCITY_CR3_GINTMSK1, vlc->regs + VELOCITY_CRC3 );
689 }
690 }
691
692 /** Velocity network device operations */
693 static struct net_device_operations velocity_operations = {
694 .open = velocity_open,
695 .close = velocity_close,
696 .transmit = velocity_transmit,
697 .poll = velocity_poll,
698 .irq = velocity_irq,
699 };
700
701 /******************************************************************************
702 *
703 * PCI interface
704 *
705 ******************************************************************************
706 */
707
708 /**
709 * Probe PCI device
710 *
711 * @v pci PCI device
712 * @ret rc Return status code
713 */
velocity_probe(struct pci_device * pci)714 static int velocity_probe ( struct pci_device *pci ) {
715 struct net_device *netdev;
716 struct velocity_nic *vlc;
717 int rc;
718
719 /* Allocate and initialise net device */
720 netdev = alloc_etherdev ( sizeof ( *vlc ) );
721 if ( ! netdev ) {
722 rc = -ENOMEM;
723 goto err_alloc;
724 }
725 netdev_init ( netdev, &velocity_operations );
726 vlc = netdev->priv;
727 pci_set_drvdata ( pci, netdev );
728 netdev->dev = &pci->dev;
729
730 /* Fix up PCI device */
731 adjust_pci_device ( pci );
732
733 /* Map registers */
734 vlc->regs = ioremap ( pci->membase, VELOCITY_BAR_SIZE );
735 vlc->netdev = netdev;
736
737 /* Reset the NIC */
738 if ( ( rc = velocity_reset ( vlc ) ) != 0 )
739 goto err_reset;
740
741 /* Reload EEPROM */
742 if ( ( rc = velocity_reload_eeprom ( vlc ) ) != 0 )
743 goto err_reset;
744
745 /* Get MAC address */
746 netdev->hw_addr[0] = readb ( vlc->regs + VELOCITY_MAC0 );
747 netdev->hw_addr[1] = readb ( vlc->regs + VELOCITY_MAC1 );
748 netdev->hw_addr[2] = readb ( vlc->regs + VELOCITY_MAC2 );
749 netdev->hw_addr[3] = readb ( vlc->regs + VELOCITY_MAC3 );
750 netdev->hw_addr[4] = readb ( vlc->regs + VELOCITY_MAC4 );
751 netdev->hw_addr[5] = readb ( vlc->regs + VELOCITY_MAC5 );
752
753 /* Initialise and reset MII interface */
754 mdio_init ( &vlc->mdio, &velocity_mii_operations );
755 mii_init ( &vlc->mii, &vlc->mdio, 0 );
756 if ( ( rc = mii_reset ( &vlc->mii ) ) != 0 ) {
757 DBGC ( vlc, "VELOCITY %p could not reset MII: %s\n",
758 vlc, strerror ( rc ) );
759 goto err_mii_reset;
760 }
761
762 /* Enable proper link advertising */
763 velocity_set_link ( vlc );
764
765 /* Register network device */
766 if ( ( rc = register_netdev ( netdev ) ) != 0 )
767 goto err_register_netdev;
768
769 return 0;
770
771 err_register_netdev:
772 err_mii_reset:
773 velocity_reset ( vlc );
774 err_reset:
775 netdev_nullify ( netdev );
776 netdev_put ( netdev );
777 err_alloc:
778 return rc;
779 }
780
781 /**
782 * Remove PCI device
783 *
784 * @v pci PCI device
785 */
velocity_remove(struct pci_device * pci)786 static void velocity_remove ( struct pci_device *pci ) {
787 struct net_device *netdev = pci_get_drvdata ( pci );
788 struct velocity_nic *vlc = netdev->priv;
789
790 /* Unregister network device */
791 unregister_netdev ( netdev );
792
793 /* Reset card */
794 velocity_reset ( vlc );
795
796 /* Free network device */
797 netdev_nullify ( netdev );
798 netdev_put ( netdev );
799 }
800
801 /** Velocity PCI device IDs */
802 static struct pci_device_id velocity_nics[] = {
803 PCI_ROM ( 0x1106, 0x3119, "vt6122", "VIA Velocity", 0 ),
804 };
805
806 /** Velocity PCI driver */
807 struct pci_driver velocity_driver __pci_driver = {
808 .ids = velocity_nics,
809 .id_count = ( sizeof ( velocity_nics ) / sizeof ( velocity_nics[0] ) ),
810 .probe = velocity_probe,
811 .remove = velocity_remove,
812 };
813