2 * Copyright (C) 2012 Adrian Jamróz <adrian.jamroz@gmail.com>
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.
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.
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
20 FILE_LICENCE ( GPL2_OR_LATER );
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>
36 #define velocity_setbit(_reg, _mask) writeb ( readb ( _reg ) | _mask, _reg )
37 #define virt_to_le32bus(x) ( cpu_to_le32 ( virt_to_bus ( x ) ) )
41 * VIA Velocity network driver
45 /******************************************************************************
49 ******************************************************************************
53 * Stop MII auto-polling
55 * @v vlc Velocity device
56 * @ret rc Return status code
58 static int velocity_autopoll_stop ( struct velocity_nic *vlc ) {
59 int timeout = VELOCITY_TIMEOUT_US;
61 /* Disable MII auto polling */
62 writeb ( 0, vlc->regs + VELOCITY_MIICR );
64 /* Wait for disabling to take effect */
67 if ( readb ( vlc->regs + VELOCITY_MIISR ) &
72 DBGC ( vlc, "MII autopoll stop timeout\n" );
77 * Start MII auto-polling
79 * @v vlc Velocity device
80 * @ret rc Return status code
82 static int velocity_autopoll_start ( struct velocity_nic *vlc ) {
83 int timeout = VELOCITY_TIMEOUT_US;
85 /* Enable MII auto polling */
86 writeb ( VELOCITY_MIICR_MAUTO, vlc->regs + VELOCITY_MIICR );
88 /* Wait for enabling to take effect */
91 if ( ( readb ( vlc->regs + VELOCITY_MIISR ) &
92 VELOCITY_MIISR_IDLE ) == 0 )
96 DBGC ( vlc, "MII autopoll start timeout\n" );
101 * Read from MII register
103 * @v mii MII interface
104 * @v reg Register address
105 * @ret value Data read, or negative error
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;
113 DBGC2 ( vlc, "VELOCITY %p MII read reg %d\n", vlc, reg );
115 /* Disable autopolling before we can access MII */
116 velocity_autopoll_stop ( vlc );
118 /* Send read command and address */
119 writeb ( reg, vlc->regs + VELOCITY_MIIADDR );
120 velocity_setbit ( vlc->regs + VELOCITY_MIICR, VELOCITY_MIICR_RCMD );
122 /* Wait for read to complete */
123 while ( timeout-- ) {
125 if ( ( readb ( vlc->regs + VELOCITY_MIICR ) &
126 VELOCITY_MIICR_RCMD ) == 0 ) {
127 result = readw ( vlc->regs + VELOCITY_MIIDATA );
128 velocity_autopoll_start ( vlc );
133 /* Restart autopolling */
134 velocity_autopoll_start ( vlc );
136 DBGC ( vlc, "MII read timeout\n" );
141 * Write to MII register
143 * @v mii MII interface
144 * @v reg Register address
145 * @v data Data to write
146 * @ret rc Return status code
148 static int velocity_mii_write ( struct mii_interface *mii, unsigned int reg,
150 struct velocity_nic *vlc =
151 container_of ( mii, struct velocity_nic, mii );
152 int timeout = VELOCITY_TIMEOUT_US;
154 DBGC2 ( vlc, "VELOCITY %p MII write reg %d data 0x%04x\n",
157 /* Disable autopolling before we can access MII */
158 velocity_autopoll_stop ( vlc );
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 );
165 /* Wait for write to complete */
166 while ( timeout-- ) {
168 if ( ( readb ( vlc->regs + VELOCITY_MIICR ) &
169 VELOCITY_MIICR_WCMD ) == 0 ) {
170 velocity_autopoll_start ( vlc );
175 /* Restart autopolling */
176 velocity_autopoll_start ( vlc );
178 DBGC ( vlc, "MII write timeout\n" );
182 /** Velocity MII operations */
183 static struct mii_operations velocity_mii_operations = {
184 .read = velocity_mii_read,
185 .write = velocity_mii_write,
191 * @v vlc Velocity device
193 static void velocity_set_link ( struct velocity_nic *vlc ) {
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 );
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 );
207 /******************************************************************************
211 ******************************************************************************
215 * Reload eeprom contents
217 * @v vlc Velocity device
219 static int velocity_reload_eeprom ( struct velocity_nic *vlc ) {
220 int timeout = VELOCITY_TIMEOUT_US;
222 /* Initiate reload */
223 velocity_setbit ( vlc->regs + VELOCITY_EECSR, VELOCITY_EECSR_RELOAD );
225 /* Wait for reload to complete */
226 while ( timeout-- ) {
228 if ( ( readb ( vlc->regs + VELOCITY_EECSR ) &
229 VELOCITY_EECSR_RELOAD ) == 0 )
233 DBGC ( vlc, "VELOCITY %p EEPROM reload timeout\n", vlc );
240 * @v vlc Velocity device
241 * @ret rc Return status code
243 static int velocity_reset ( struct velocity_nic *vlc ) {
244 int timeout = VELOCITY_TIMEOUT_US;
247 DBGC ( vlc, "VELOCITY %p reset\n", vlc );
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 );
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 );
259 velocity_setbit ( vlc->regs + VELOCITY_CRS1, VELOCITY_CR1_SFRST );
261 /* Wait for reset to complete */
262 while ( timeout-- ) {
264 if ( ( readb ( vlc->regs + VELOCITY_CRS1 ) &
265 VELOCITY_CR1_SFRST ) == 0 )
272 /******************************************************************************
276 ******************************************************************************
282 * @v netdev Network device
284 static void velocity_check_link ( struct net_device *netdev ) {
285 struct velocity_nic *vlc = netdev->priv;
287 if ( readb ( vlc->regs + VELOCITY_PHYSTS0 ) & VELOCITY_PHYSTS0_LINK ) {
288 netdev_link_up ( netdev );
289 DBGC ( vlc, "VELOCITY %p link up\n", vlc );
291 netdev_link_down ( netdev );
292 DBGC ( vlc, "VELOCITY %p link down\n", vlc );
295 /* The card disables auto-poll after a link change */
296 velocity_autopoll_start ( vlc );
299 /******************************************************************************
301 * Network device interface
303 ******************************************************************************
307 * Allocate descriptor rings
309 * @v vlc Velocity device
310 * @ret rc Return status code
312 static int velocity_alloc_rings ( struct velocity_nic *vlc ) {
315 /* Allocate RX descriptor ring */
319 vlc->rx_ring = malloc_dma ( VELOCITY_RXDESC_SIZE, VELOCITY_RING_ALIGN );
320 if ( ! vlc->rx_ring )
323 memset ( vlc->rx_ring, 0, VELOCITY_RXDESC_SIZE );
325 DBGC2 ( vlc, "VELOCITY %p RX ring start address: %p(phys: %#08lx)\n",
326 vlc, vlc->rx_ring, virt_to_bus ( vlc->rx_ring ) );
328 /* Allocate TX descriptor ring */
331 vlc->tx_ring = malloc_dma ( VELOCITY_TXDESC_SIZE, VELOCITY_RING_ALIGN );
332 if ( ! vlc->tx_ring ) {
337 memset ( vlc->tx_ring, 0, VELOCITY_TXDESC_SIZE );
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 );
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 );
349 DBGC2 ( vlc, "VELOCITY %p TX ring start address: %p(phys: %#08lx)\n",
350 vlc, vlc->tx_ring, virt_to_bus ( vlc->tx_ring ) );
355 free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE );
360 * Refill receive descriptor ring
362 * @v vlc Velocity device
364 static void velocity_refill_rx ( struct velocity_nic *vlc ) {
365 struct velocity_rx_descriptor *desc;
366 struct io_buffer *iobuf;
369 /* Check for new packets */
370 while ( ( vlc->rx_prod - vlc->rx_cons ) < VELOCITY_RXDESC_NUM ) {
371 iobuf = alloc_iob ( VELOCITY_RX_MAX_LEN );
373 /* Memory pressure: try again next poll */
377 rx_idx = ( vlc->rx_prod++ % VELOCITY_RXDESC_NUM );
378 desc = &vlc->rx_ring[rx_idx];
380 /* Set descrptor fields */
382 desc->addr = virt_to_le32bus ( iobuf-> data );
383 desc->des2 = cpu_to_le32 (
384 VELOCITY_DES2_SIZE ( VELOCITY_RX_MAX_LEN - 1 ) |
387 vlc->rx_buffs[rx_idx] = iobuf;
390 /* Return RX descriptors in blocks of 4 (hw requirement) */
391 if ( rx_idx % 4 == 3 ) {
393 for (j = 0; j < 4; j++) {
394 desc = &vlc->rx_ring[rx_idx - j];
395 desc->des0 = cpu_to_le32 ( VELOCITY_DES0_OWN );
403 if ( vlc->rx_commit ) {
404 writew ( vlc->rx_commit,
405 vlc->regs + VELOCITY_RXDESC_RESIDUECNT );
410 DBGC2 ( vlc, "VELOCITY %p refilled %d RX descriptors\n",
415 * Open network device
417 * @v netdev Network device
418 * @ret rc Return status code
420 static int velocity_open ( struct net_device *netdev ) {
421 struct velocity_nic *vlc = netdev->priv;
424 DBGC ( vlc, "VELOCITY %p open\n", vlc );
425 DBGC ( vlc, "VELOCITY %p regs at: %p\n", vlc, vlc->regs );
427 /* Allocate descriptor rings */
428 if ( ( rc = velocity_alloc_rings ( vlc ) ) != 0 )
431 velocity_refill_rx ( vlc );
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 );
438 /* Enable interrupts */
439 writeb ( 0xff, vlc->regs + VELOCITY_IMR0 );
440 writeb ( 0xff, vlc->regs + VELOCITY_IMR1 );
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 );
448 /* Receive all packets */
449 writeb ( 0xff, vlc->regs + VELOCITY_RCR );
451 /* Set initial link state */
452 velocity_check_link ( netdev );
454 velocity_autopoll_start ( vlc );
456 DBGC2 ( vlc, "VELOCITY %p CR3 %02x\n",
457 vlc, readb ( vlc->regs + 0x0B ) );
463 * Close network device
465 * @v netdev Network device
467 static void velocity_close ( struct net_device *netdev ) {
468 struct velocity_nic *vlc = netdev->priv;
472 writeb ( VELOCITY_CR0_TXON | VELOCITY_CR0_RXON,
473 vlc->regs + VELOCITY_CRC0 );
474 writeb ( VELOCITY_CR0_STOP, vlc->regs + VELOCITY_CRS0 );
476 /* Clear RX ring information */
477 writel ( 0, vlc->regs + VELOCITY_RXDESC_ADDR_LO );
478 writew ( 0, vlc->regs + VELOCITY_RXDESCNUM );
480 /* Destroy RX ring */
481 free_dma ( vlc->rx_ring, VELOCITY_RXDESC_SIZE );
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;
493 /* Clear TX ring information */
494 writel ( 0, vlc->regs + VELOCITY_TXDESC_ADDR_LO0 );
495 writew ( 0, vlc->regs + VELOCITY_TXDESCNUM );
497 /* Destroy TX ring */
498 free_dma ( vlc->tx_ring, VELOCITY_TXDESC_SIZE );
507 * @v netdev Network device
508 * @v iobuf I/O buffer
509 * @ret rc Return status code
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;
517 /* Pad packet to minimum length */
518 iob_pad ( iobuf, ETH_ZLEN );
520 tx_idx = ( vlc->tx_prod++ % VELOCITY_TXDESC_NUM );
521 desc = &vlc->tx_ring[tx_idx];
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 );
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 ) ) );
538 velocity_setbit ( vlc->regs + VELOCITY_TXQCSRS, VELOCITY_TXQCSRS_WAK0 );
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 ) );
547 * Poll for received packets.
549 * @v vlc Velocity device
551 static void velocity_poll_rx ( struct velocity_nic *vlc ) {
552 struct velocity_rx_descriptor *desc;
553 struct io_buffer *iobuf;
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];
563 des0 = cpu_to_le32 ( desc->des0 );
565 /* Return if descriptor still in use */
566 if ( des0 & VELOCITY_DES0_OWN )
569 iobuf = vlc->rx_buffs[rx_idx];
571 /* Get length, strip CRC */
572 len = VELOCITY_DES0_RMBC ( des0 ) - 4;
573 iob_put ( iobuf, len );
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 );
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",
583 } else if ( des0 & VELOCITY_DES0_RXOK ) {
584 /* Report receive success */
585 netdev_rx( vlc->netdev, iobuf );
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",
592 DBGC ( vlc, "packet len: %zd\n", len );
593 DBGC_HD ( vlc, iobuf->data, 64 );
595 /* we don't know what it is, treat is as an error */
596 netdev_rx_err ( vlc->netdev, iobuf, -EINVAL );
604 * Poll for completed packets.
606 * @v vlc Velocity device
608 static void velocity_poll_tx ( struct velocity_nic *vlc ) {
609 struct velocity_tx_descriptor *desc;
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];
617 /* Return if descriptor still in use */
618 if ( le32_to_cpu ( desc->des0 ) & VELOCITY_DES0_OWN )
622 if ( le32_to_cpu ( desc->des0 ) & VELOCITY_DES0_TERR ) {
623 netdev_tx_complete_next_err ( vlc->netdev, -EINVAL );
627 netdev_tx_complete_next ( vlc->netdev );
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 ) );
637 * Poll for completed and received packets
639 * @v netdev Network device
641 static void velocity_poll ( struct net_device *netdev ) {
642 struct velocity_nic *vlc = netdev->priv;
645 isr1 = readb ( vlc->regs + VELOCITY_ISR1 );
648 writew ( 0xFFFF, vlc->regs + VELOCITY_ISR0 );
650 /* Check for competed packets */
651 velocity_poll_rx ( vlc );
652 velocity_poll_tx ( vlc );
654 if ( isr1 & VELOCITY_ISR1_SRCI ) {
655 /* Update linkstate */
656 DBGC2 ( vlc, "VELOCITY %p link status interrupt\n", vlc );
657 velocity_check_link ( netdev );
660 velocity_refill_rx ( vlc );
662 /* deal with potential RX stall caused by RX ring underrun */
663 writew ( VELOCITY_RXQCSR_RUN | VELOCITY_RXQCSR_WAK,
664 vlc->regs + VELOCITY_RXQCSRS );
668 * Enable or disable interrupts
670 * @v netdev Network device
671 * @v enable Interrupts should be enabled
673 static void velocity_irq ( struct net_device *netdev, int enable ) {
674 struct velocity_nic *vlc = netdev->priv;
676 DBGC ( vlc, "VELOCITY %p interrupts %s\n", vlc,
677 enable ? "enable" : "disable" );
680 /* Enable interrupts */
681 writeb ( VELOCITY_CR3_GINTMSK1, vlc->regs + VELOCITY_CRS3 );
683 /* Disable interrupts */
684 writeb ( VELOCITY_CR3_GINTMSK1, vlc->regs + VELOCITY_CRC3 );
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,
697 /******************************************************************************
701 ******************************************************************************
708 * @ret rc Return status code
710 static int velocity_probe ( struct pci_device *pci ) {
711 struct net_device *netdev;
712 struct velocity_nic *vlc;
715 /* Allocate and initialise net device */
716 netdev = alloc_etherdev ( sizeof ( *vlc ) );
721 netdev_init ( netdev, &velocity_operations );
723 pci_set_drvdata ( pci, netdev );
724 netdev->dev = &pci->dev;
726 /* Fix up PCI device */
727 adjust_pci_device ( pci );
730 vlc->regs = ioremap ( pci->membase, VELOCITY_BAR_SIZE );
731 vlc->netdev = netdev;
734 if ( ( rc = velocity_reset ( vlc ) ) != 0 )
738 if ( ( rc = velocity_reload_eeprom ( vlc ) ) != 0 )
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 );
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 ) );
757 /* Enable proper link advertising */
758 velocity_set_link ( vlc );
760 /* Register network device */
761 if ( ( rc = register_netdev ( netdev ) ) != 0 )
762 goto err_register_netdev;
768 velocity_reset ( vlc );
770 netdev_nullify ( netdev );
771 netdev_put ( netdev );
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;
785 /* Unregister network device */
786 unregister_netdev ( netdev );
789 velocity_reset ( vlc );
791 /* Free network device */
792 netdev_nullify ( netdev );
793 netdev_put ( netdev );
796 /** Velocity PCI device IDs */
797 static struct pci_device_id velocity_nics[] = {
798 PCI_ROM ( 0x1106, 0x3119, "vt6122", "VIA Velocity", 0 ),
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,