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