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