~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to roms/ipxe/src/drivers/net/velocity.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
};