source: SVN/cambria/redboot/packages/devs/eth/intel/npe/common/current/src/if_npe.c @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 42.9 KB
Line 
1//==========================================================================
2//
3//      if_npe.c
4//
5//      Intel NPE ethernet driver
6//
7//==========================================================================
8//####ECOSGPLCOPYRIGHTBEGIN####
9// -------------------------------------------
10// This file is part of eCos, the Embedded Configurable Operating System.
11// Copyright 2002-2003 Intel Corporation All Rights Reserved.
12//
13// eCos is free software; you can redistribute it and/or modify it under
14// the terms of the GNU General Public License as published by the Free
15// Software Foundation; either version 2 or (at your option) any later version.
16//
17// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20// for more details.
21//
22// You should have received a copy of the GNU General Public License along
23// with eCos; if not, write to the Free Software Foundation, Inc.,
24// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25//
26// As a special exception, if other files instantiate templates or use macros
27// or inline functions from this file, or you compile this file and link it
28// with other works to produce a work based on this file, this file does not
29// by itself cause the resulting work to be covered by the GNU General Public
30// License. However the source code for this file must still be made available
31// in accordance with section (3) of the GNU General Public License.
32//
33// This exception does not invalidate any other reasons why a work based on
34// this file might be covered by the GNU General Public License.
35//
36// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37// at http://sources.redhat.com/ecos/ecos-license/
38// -------------------------------------------
39//####ECOSGPLCOPYRIGHTEND####
40//==========================================================================
41//#####DESCRIPTIONBEGIN####
42//
43// Author(s):    msalter
44// Contributors: msalter
45// Date:         2003-03-20
46// Purpose:     
47// Description:  hardware driver for Intel Network Processors.
48// Notes:
49//
50//####DESCRIPTIONEND####
51//
52//==========================================================================
53
54#include <pkgconf/system.h>
55#include <pkgconf/io_eth_drivers.h>
56#include <pkgconf/devs_eth_intel_npe.h>
57#include <cyg/infra/cyg_type.h>
58#include <cyg/infra/cyg_ass.h>
59#include <cyg/hal/hal_arch.h>
60#include <cyg/hal/hal_cache.h>
61#include <cyg/hal/hal_intr.h>
62#include <cyg/infra/diag.h>
63#include <cyg/hal/hal_if.h>
64#include <cyg/hal/drv_api.h>
65#include <cyg/io/eth/netdev.h>
66#include <cyg/io/eth/eth_drv.h>
67
68#include <IxOsal.h>
69#include <IxEthAcc.h>
70#include <IxEthDB.h>
71#include <IxNpeDl.h>
72#include <IxQMgr.h>
73#include <IxNpeMh.h>
74#include <ix_ossl.h>
75#include <IxFeatureCtrl.h>
76
77#include <npe_info.h>
78
79#ifdef CYGPKG_REDBOOT
80#include <pkgconf/redboot.h>
81#include <redboot.h>
82#include <flash_config.h>
83#endif
84
85// #define DEBUG
86
87#define NPE_NUM_PORTS 3
88
89static IxQMgrDispatcherFuncPtr qDispatcherFunc;
90static int npe_exists[NPE_NUM_PORTS];
91static int npe_used[NPE_NUM_PORTS];
92static BOOL phy_exists[IXP425_ETH_ACC_MII_MAX_ADDR];
93static BOOL phy_scanned[IXP425_ETH_ACC_MII_MAX_ADDR];
94static BOOL phy_inited[IXP425_ETH_ACC_MII_MAX_ADDR];
95static const char *npe_names[NPE_NUM_PORTS] = {
96    "NPE-B", "NPE-C", "NPE-A"
97};
98
99// Convert IX_ETH_PORT_n to IX_NPEMH_NPEID_NPEx
100static inline int __eth_to_npe(int eth_id)
101{
102    switch(eth_id) {
103    case IX_ETH_PORT_1: return IX_NPEMH_NPEID_NPEB;
104    case IX_ETH_PORT_2: return IX_NPEMH_NPEID_NPEC;
105    case IX_ETH_PORT_3: return IX_NPEMH_NPEID_NPEA;
106    }
107    return 0;
108}
109
110// Poll the CSR machinery.
111static inline void __npe_poll(int eth_id)
112{
113    extern void ixEthAccMacRecoveryPoll(void);
114
115    ixNpeMhMessagesReceive(__eth_to_npe(eth_id));
116    (*qDispatcherFunc)(IX_QMGR_QUELOW_GROUP);
117    ixEthAccMacRecoveryPoll();
118}
119
120static inline int __npe_poll_timed(int eth_id, int *flagp, unsigned ms)
121{
122    do {
123        __npe_poll(eth_id);
124        if (ms) {
125            CYGACC_CALL_IF_DELAY_US(1000);
126            --ms;
127        }
128    } while (!*flagp && ms);
129
130    return *flagp;
131}
132
133#define NPE_INT_BITS ((1 << CYGNUM_HAL_INTERRUPT_NPEB) | \
134                      (1 << CYGNUM_HAL_INTERRUPT_NPEC) | \
135                      (1 << CYGNUM_HAL_INTERRUPT_QM1))
136
137// Can't use SMII without NPE-B
138#if CYGINT_DEVS_ETH_INTEL_NPEB_SMII
139#define CYGSEM_NPE_SMII
140#else
141#if CYGINT_DEVS_ETH_INTEL_NPEA_SMII
142#error Cannot use SMII for NPE-A without SMII for NPE-B
143#endif
144#if CYGINT_DEVS_ETH_INTEL_NPEC_SMII
145#error Cannot use SMII for NPE-C without SMII for NPE-B
146#endif
147#endif
148
149static int  npe_csr_load(void);
150static int  phy_present(int phyno);
151static int  phy_init(int phyno, BOOL autoneg, int timeout);
152static int  mac_init(int portno, int phyno);
153static int  link_check(unsigned int phyNo, int timeout);
154#if CYGINT_DEVS_ETH_INTEL_NPE_PHY_DISCOVERY
155static void npe_csr_unload(void);
156static int  check_phy_association(int portno, int phyno);
157static void set_phy_association(int portno, int phyno);
158static void set_phy_mask(int portno, cyg_uint32 phymask);
159#endif
160#ifdef CYGSEM_NPE_SMII
161static int  npe_enable_smii_mode(cyg_uint32 mask);
162static int  reset_npes(cyg_uint32 mask);
163static void unreset_npes(cyg_uint32 mask);
164#endif
165
166#include CYGDAT_DEVS_ETH_INTEL_NPE_INL
167
168#ifdef CYGSEM_INTEL_NPE_USE_ETH0
169#define __NUM_ETH0_PORTS 1
170static struct npe npe_eth0_priv_data = { 
171    eth_id: CYGNUM_ETH0_ETH_ID,
172    phy_no: CYGNUM_ETH0_PHY_NO,
173#if defined(CYGNUM_ETH0_PHY_MASK)
174    phy_mask: CYGNUM_ETH0_PHY_MASK,
175#endif
176#if defined(CYGDAT_ETH0_DEFAULT_ESA)
177    mac_address: CYGDAT_ETH0_DEFAULT_ESA
178#endif
179};
180#else
181#define __NUM_ETH0_PORTS 0
182#endif
183
184#ifdef CYGSEM_INTEL_NPE_USE_ETH1
185#define __NUM_ETH1_PORTS 1
186static struct npe npe_eth1_priv_data = { 
187    eth_id: CYGNUM_ETH1_ETH_ID,
188    phy_no: CYGNUM_ETH1_PHY_NO,
189#if defined(CYGNUM_ETH1_PHY_MASK)
190    phy_mask: CYGNUM_ETH1_PHY_MASK,
191#endif
192#if defined(CYGDAT_ETH1_DEFAULT_ESA)
193    mac_address: CYGDAT_ETH1_DEFAULT_ESA
194#endif
195};
196#else
197#define __NUM_ETH1_PORTS 0
198#endif
199
200#ifdef CYGSEM_INTEL_NPE_USE_ETH2
201#define __NUM_ETH2_PORTS 1
202static struct npe npe_eth2_priv_data = { 
203    eth_id: CYGNUM_ETH2_ETH_ID,
204    phy_no: CYGNUM_ETH2_PHY_NO,
205#if defined(CYGNUM_ETH2_PHY_MASK)
206    phy_mask: CYGNUM_ETH2_PHY_MASK,
207#endif
208#if defined(CYGDAT_ETH2_DEFAULT_ESA)
209    mac_address: CYGDAT_ETH2_DEFAULT_ESA
210#endif
211};
212#else
213#define __NUM_ETH2_PORTS 0
214#endif
215
216#ifdef CYGPKG_DEVS_ETH_INTEL_NPE_REDBOOT_HOLDS_UTOPIA_FLAG_VAR
217RedBoot_config_option("Utopia on NPE-A",
218                      utopia,
219                      ALWAYS_ENABLED, true,
220                      CONFIG_BOOL,
221                      CYGDAT_DEVS_ETH_INTEL_NPE_DEFAULT_UTOPIA_FLAG
222    );
223#endif // CYGPKG_DEVS_ETH_INTEL_NPE_REDBOOT_HOLDS_UTOPIA_FLAG_VAR
224#ifdef CYGPKG_DEVS_ETH_INTEL_NPE_REDBOOT_HOLDS_ESA_VARS
225#define RedBoot_npe_esa_config_option(_n_,_t_,_x_,_e_,_ie_,_type_,_dflt_)  \
226struct config_option _config_option_##_x_                                  \
227CYG_HAL_TABLE_QUALIFIED_ENTRY(RedBoot_config_options,_x_) =                \
228   {_n_,_t_,_e_,_ie_,_type_,(unsigned long)_dflt_};
229#ifdef CYGSEM_INTEL_NPE_USE_ETH0
230RedBoot_npe_esa_config_option(
231        "npe_" CYGDAT_NPE_ETH0_NAME "_esa",
232        "Network hardware address [MAC] for npe_" CYGDAT_NPE_ETH0_NAME,
233        npe_eth0_esa,
234        ALWAYS_ENABLED, true,
235        CONFIG_ESA, npe_eth0_priv_data.mac_address
236    );
237#endif //CYGSEM_INTEL_NPE_USE_ETH0
238
239#ifdef CYGSEM_INTEL_NPE_USE_ETH1
240RedBoot_npe_esa_config_option(
241        "npe_" CYGDAT_NPE_ETH1_NAME "_esa",
242        "Network hardware address [MAC] for npe_" CYGDAT_NPE_ETH1_NAME,
243        npe_eth1_esa,
244        ALWAYS_ENABLED, true,
245        CONFIG_ESA, npe_eth1_priv_data.mac_address
246    );
247#endif // CYGSEM_INTEL_NPE_USE_ETH1
248
249#ifdef CYGSEM_INTEL_NPE_USE_ETH2
250RedBoot_npe_esa_config_option(
251        "npe_" CYGDAT_NPE_ETH2_NAME "_esa",
252        "Network hardware address [MAC] for npe_" CYGDAT_NPE_ETH2_NAME,
253        npe_eth2_esa,
254        ALWAYS_ENABLED, true,
255        CONFIG_ESA, npe_eth2_priv_data.mac_address
256    );
257#endif // CYGSEM_INTEL_NPE_USE_ETH1
258#endif // CYGPKG_DEVS_ETH_INTEL_NPE_REDBOOT_HOLDS_ESA_VARS
259
260#define MAX_PORTS (__NUM_ETH0_PORTS + __NUM_ETH1_PORTS + __NUM_ETH2_PORTS)
261
262#ifdef CYGPKG_REDBOOT
263#define ACTIVE_PORTS 1
264#else
265#define ACTIVE_PORTS MAX_PORTS
266#endif
267
268#define NPE_PKT_SIZE 1600
269
270#define NPE_MBUF_POOL_SIZE                               \
271        ((CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS + \
272         CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS) * \
273        sizeof(IX_OSAL_MBUF) * ACTIVE_PORTS)
274
275#define NPE_PKT_POOL_SIZE                                \
276        ((CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS + \
277         CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS) * \
278        NPE_PKT_SIZE * ACTIVE_PORTS)
279
280#define NPE_MEM_POOL_SIZE (NPE_MBUF_POOL_SIZE + NPE_PKT_POOL_SIZE)
281
282
283// A little extra so we can align to cacheline.
284static cyg_uint8 npe_alloc_pool[NPE_MEM_POOL_SIZE + HAL_DCACHE_LINE_SIZE - 1];
285static cyg_uint8 *npe_alloc_end;
286static cyg_uint8 *npe_alloc_free;
287
288static void*
289npe_alloc(int size)
290{
291    void *p = NULL;
292
293    size = (size + (HAL_DCACHE_LINE_SIZE-1)) & ~(HAL_DCACHE_LINE_SIZE-1);
294    if ((npe_alloc_free + size) < npe_alloc_end) {
295        p = npe_alloc_free;
296        npe_alloc_free += size;
297    }
298    return p;
299}
300
301
302// Not interrupt safe!
303static void
304mbuf_enqueue(IX_OSAL_MBUF **q, IX_OSAL_MBUF *new)
305{
306    IX_OSAL_MBUF *m = *q;
307
308    IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(new) = NULL;
309
310    if (m) {
311        while(IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m))
312            m = IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m);
313        IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m) = new;
314    } else
315        *q = new;
316}
317
318// Not interrupt safe!
319static IX_OSAL_MBUF *
320mbuf_dequeue(IX_OSAL_MBUF **q)
321{
322    IX_OSAL_MBUF *m = *q;
323    if (m)
324        *q = IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m);
325    return m;
326}
327
328static void
329reset_tx_mbufs(struct npe* p_npe)
330{
331    IX_OSAL_MBUF *m;
332    int i;
333
334    p_npe->txQHead = NULL;
335
336    for (i = 0; i < CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS; i++) {
337        m = &p_npe->tx_mbufs[i];
338
339        memset(m, 0, sizeof(*m));
340
341        IX_OSAL_MBUF_MDATA(m) = (void *)&p_npe->tx_pkts[i * NPE_PKT_SIZE];
342#ifdef __LITTLE_ENDIAN
343        IX_OSAL_MBUF_MDATA(m) = (void *)(((unsigned)IX_OSAL_MBUF_MDATA(m)) | SDRAM_DC_BASE);
344#endif
345        IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE;
346        mbuf_enqueue(&p_npe->txQHead, m);
347    }
348}
349
350static void
351reset_rx_mbufs(struct npe* p_npe)
352{
353    IX_OSAL_MBUF *m;
354    int i;
355
356    p_npe->rxQHead = NULL;
357
358    HAL_DCACHE_INVALIDATE(p_npe->rx_pkts, NPE_PKT_SIZE *
359                          CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
360 
361    for (i = 0; i < CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS; i++) {
362        m = &p_npe->rx_mbufs[i];
363
364        memset(m, 0, sizeof(*m));
365
366        IX_OSAL_MBUF_MDATA(m) = (void *)&p_npe->rx_pkts[i * NPE_PKT_SIZE];
367#ifdef __LITTLE_ENDIAN
368        IX_OSAL_MBUF_MDATA(m) = (void *)(((unsigned)IX_OSAL_MBUF_MDATA(m)) | SDRAM_DC_BASE);
369#endif
370        IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE;
371
372        if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) {
373#ifdef DEBUG
374            diag_printf("ixEthAccPortRxFreeReplenish failed for port %d\n",
375                        p_npe->eth_id);
376#endif
377            break;
378        }
379    }
380}
381
382static void
383init_rx_mbufs(struct npe* p_npe)
384{
385    p_npe->rxQHead = NULL;
386
387    p_npe->rx_pkts = npe_alloc(NPE_PKT_SIZE *
388                               CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
389    if (p_npe->rx_pkts == NULL) {
390#ifdef DEBUG
391        diag_printf("alloc of packets failed.\n");
392#endif
393        return;
394    }
395
396    p_npe->rx_mbufs = (IX_OSAL_MBUF *)npe_alloc(sizeof(IX_OSAL_MBUF) *
397                                         CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
398    if (p_npe->rx_mbufs == NULL) {
399#ifdef DEBUG
400        diag_printf("alloc of mbufs failed.\n");
401#endif
402        return;
403    }
404
405    reset_rx_mbufs(p_npe);
406}
407
408
409static void
410init_tx_mbufs(struct npe* p_npe)
411{
412    p_npe->tx_pkts = npe_alloc(NPE_PKT_SIZE *
413                               CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS);
414    if (p_npe->tx_pkts == NULL) {
415#ifdef DEBUG
416        diag_printf("alloc of packets failed.\n");
417#endif
418        return;
419    }
420
421    p_npe->tx_mbufs = (IX_OSAL_MBUF *)npe_alloc(sizeof(IX_OSAL_MBUF) *
422                                         CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS);
423    if (p_npe->tx_mbufs == NULL) {
424#ifdef DEBUG
425        diag_printf("alloc of mbufs failed.\n");
426#endif
427        return;
428    }
429
430    reset_tx_mbufs(p_npe);
431}
432
433// Returns non-zero if link is up. Wait up to timeout milliseconds.
434static int
435link_check(unsigned int phyNo, int timeout)
436{
437    BOOL fullDuplex, linkUp, speed, autoneg;
438
439    ixEthAccMiiLinkStatus(phyNo, &linkUp, &speed, &fullDuplex, &autoneg);
440    if (linkUp == FALSE) {
441#ifdef DEBUG
442        diag_printf("Wait for PHY %u to be ready ...", phyNo);
443#endif
444        while (linkUp == FALSE && timeout > 0) {
445            CYGACC_CALL_IF_DELAY_US((cyg_int32)100000);
446            ixEthAccMiiLinkStatus(phyNo, &linkUp, &speed, &fullDuplex, &autoneg);
447            timeout -= 100;
448        }
449        if (linkUp == FALSE) {
450#ifdef DEBUG
451            diag_printf("timeout!\n");
452#endif
453            return 0;
454        }
455    }
456#ifdef DEBUG
457        diag_printf("success.\n");
458#endif
459    return 1;
460}
461
462// Returns non-zero if given PHY is present.
463static int
464phy_present(int phyno)
465{
466    if (phyno < 0 || phyno >= IXP425_ETH_ACC_MII_MAX_ADDR)
467        return 0;
468
469    if (!phy_scanned[phyno]) {
470        if (ixEthMiiPhyPresent(phyno, &phy_exists[phyno]) != IX_ETH_ACC_SUCCESS)
471            return 0;
472        phy_scanned[phyno] = 1;
473    }
474    return  phy_exists[phyno];
475}
476
477#if defined(CYGSEM_NPE_SMII)
478static int
479reset_npes(cyg_uint32 mask)
480{
481    cyg_uint32 timeout;
482    cyg_uint32 resetMask = 0;
483
484    if (mask & (1 << IX_ETH_PORT_1))
485        resetMask |= (1 << IX_FEATURECTRL_NPEB);
486    if (mask & (1 << IX_ETH_PORT_2))
487        resetMask |= (1 << IX_FEATURECTRL_NPEC);
488    if (mask & (1 << IX_ETH_PORT_3))
489        resetMask |= (1 << IX_FEATURECTRL_NPEA);
490
491    ixFeatureCtrlWrite(ixFeatureCtrlRead() | resetMask);
492
493    // wait for up to 5 seconds
494    for (timeout = 5000; timeout; timeout--) {
495        CYGACC_CALL_IF_DELAY_US(1000);
496        if ((ixFeatureCtrlRead() & resetMask) == resetMask)
497            return 1;
498    }
499    return 0;
500}
501
502static void
503unreset_npes(cyg_uint32 mask)
504{
505    cyg_uint32 resetMask = 0;
506
507    if (mask & (1 << IX_ETH_PORT_1))
508        resetMask |= (1 << IX_FEATURECTRL_NPEB);
509    if (mask & (1 << IX_ETH_PORT_2))
510        resetMask |= (1 << IX_FEATURECTRL_NPEC);
511    if (mask & (1 << IX_ETH_PORT_3))
512        resetMask |= (1 << IX_FEATURECTRL_NPEA);
513
514    ixFeatureCtrlWrite(ixFeatureCtrlRead() & ~resetMask);
515}
516
517static int
518npe_enable_smii_mode(cyg_uint32 mask)
519{
520    cyg_uint32 smiiMask = 0;
521
522    // Disable NPE-B Ethernet 1-3 Coprocessors
523    ixFeatureCtrlWrite(ixFeatureCtrlRead() | (1 << IX_FEATURECTRL_NPEB_ETH));
524
525    if (!reset_npes(mask))
526        return 0;
527
528    *IXP400_EXP_SMII_RCOMP_CSR |= (1 << 16);
529
530    *IXP400_EXP_SMIIDLL = CYGDAT_NPE_SMII_DLL_SETTING;
531
532    if (mask & (1 << IX_ETH_PORT_1))
533        smiiMask |= EXP_CNFG1_NPEB_SMII;
534    if (mask & (1 << IX_ETH_PORT_2))
535        smiiMask |= EXP_CNFG1_NPEC_SMII;
536    if (mask & (1 << IX_ETH_PORT_3))
537        smiiMask |= EXP_CNFG1_NPEA_SMII;
538
539    *IXP425_EXP_CNFG1 |= smiiMask;
540
541    CYGACC_CALL_IF_DELAY_US(50);
542
543    if ((*IXP425_EXP_CNFG1 & smiiMask) != smiiMask)
544        return 0;
545
546    unreset_npes(mask);
547
548    // delay to allow lines to settle
549    CYGACC_CALL_IF_DELAY_US(20000);
550
551    return 1;
552}
553
554#if !defined(CYGHAL_NPE_SMII_INIT)
555static int
556do_enable_smii_mode(void)
557{
558    int mask = 0;
559
560#if CYGINT_DEVS_ETH_INTEL_NPEB_SMII
561    mask |= (1 << IX_ETH_PORT_1);
562#endif
563#if CYGINT_DEVS_ETH_INTEL_NPEC_SMII
564    if (npe_used[IX_ETH_PORT_2] && npe_exists[IX_ETH_PORT_2])
565        mask |= (1 << IX_ETH_PORT_2);
566#endif
567#if CYGINT_DEVS_ETH_INTEL_NPEA_SMII
568    if (npe_used[IX_ETH_PORT_3] && npe_exists[IX_ETH_PORT_3])
569        mask |= (1 << IX_ETH_PORT_3);
570#endif
571
572    return npe_enable_smii_mode(mask);
573}
574#endif  // !defined(CYGHAL_NPE_SMII_INIT)
575#endif  // CYGSEM_NPE_SMII
576
577// Returns non-zero if NPE-A is being used for UTOPIA
578static int
579utopia_enabled(void)
580{
581#if defined(CYGHWR_HAL_ARM_XSCALE_CPU_IXP46x) || defined(CYGHWR_HAL_ARM_XSCALE_CPU_IXP43x)
582    if (ixFeatureCtrlDeviceRead() == IX_FEATURE_CTRL_DEVICE_TYPE_IXP46X ||
583        ixFeatureCtrlDeviceRead() == IX_FEATURE_CTRL_DEVICE_TYPE_IXP43X) {
584#ifdef CYGPKG_DEVS_ETH_INTEL_NPE_REDBOOT_HOLDS_UTOPIA_FLAG
585        bool ok, val;
586
587        ok = false;
588        ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET,
589                                         "utopia", &val, CONFIG_BOOL);
590        return (ok && val);
591#else
592#ifdef CYGDAT_DEVS_ETH_INTEL_NPE_UTOPIA_FLAG
593        return CYGDAT_DEVS_ETH_INTEL_NPE_UTOPIA_FLAG;
594#else
595#error No method for getting UTOPIA flag.
596#endif
597#endif // CYGPKG_DEVS_ETH_INTEL_NPE_REDBOOT_HOLDS_UTOPIA_FLAG
598    }
599#endif // CYGHWR_HAL_ARM_XSCALE_CPU_IXP46x || CYGHWR_HAL_ARM_XSCALE_CPU_IXP43x
600
601    // npe_a is used for UTOPIA
602    return 1;
603}
604
605#if CYGINT_DEVS_ETH_INTEL_NPE_PHY_DISCOVERY
606/*
607 * Some platforms may have jumper configurations which change the connection
608 * between NPE engines and PHYs. This routine tries to determine if the given
609 * NPE port is connected to the given PHY. It accomplishes this by putting
610 * the PHY into loopback mode and seeing if the NPE port can send itself a
611 * packet through that loopback.
612 */
613static int loop_txdone;
614static int loop_rxdone;
615static int loop_rxmatch;
616
617static void
618loop_tx_callback(cyg_uint32 cbTag, IX_OSAL_MBUF *m)
619{
620#ifdef DEBUG
621    char *pkt = IX_OSAL_MBUF_MDATA(m);
622
623    diag_printf("loop_tx_callback: m[%x] data[%x] len[%d] port[%d] phy[%d]\n",
624                m, pkt, IX_OSAL_MBUF_MLEN(m), pkt[0], pkt[1]);
625#endif
626    loop_txdone = 1;
627}
628
629static void
630loop_rx_callback(cyg_uint32 cbTag, IX_OSAL_MBUF *m, IxEthAccPortId portid)
631{
632    char *pkt = IX_OSAL_MBUF_MDATA(m);
633
634    loop_rxdone = 1;
635
636    if (!strcmp(pkt+14, "Hello"))
637        loop_rxmatch = 1;
638
639#ifdef DEBUG
640    diag_printf("loop_rx_callback: m[%x] data[%x] found[%d] portid[%d] port[%d] phy[%d]\n",
641                m, IX_OSAL_MBUF_MDATA(m), loop_rxmatch, portid, pkt[0], pkt[1]);
642#endif
643    HAL_DCACHE_INVALIDATE(IX_OSAL_MBUF_MDATA(m), NPE_PKT_SIZE);
644}
645
646static int
647check_phy_association(int portno, int phyno)
648{
649    IX_OSAL_MBUF  *rxmb, *txmb;
650    cyg_uint8 *rxpkt, *txpkt, *p;
651    int i;
652
653    if (portno < 0 || portno >= NPE_NUM_PORTS || !npe_exists[portno])
654        return 0;
655
656    if (!phy_present(phyno))
657        return 0;
658
659    if (!(phy_inited[phyno])) {
660        phy_inited[phyno] = 1;
661        phy_init(phyno, FALSE, 1000);
662    }
663
664    ixEthMiiPhyLoopbackEnable(phyno);
665    if (!mac_init(portno, phyno)) {
666        diag_printf("MAC init error!\n");
667        return 0;
668    }
669
670    // carve out a chunk of free memory for temporary use
671    p = npe_alloc_free;
672    rxpkt = p; p += NPE_PKT_SIZE;
673    txpkt = p; p += NPE_PKT_SIZE;
674#ifdef __LITTLE_ENDIAN
675    rxpkt = (void *)((unsigned)rxpkt | SDRAM_DC_BASE);
676    txpkt = (void *)((unsigned)txpkt | SDRAM_DC_BASE);
677#endif
678    rxmb = (IX_OSAL_MBUF *)p; p += sizeof(IX_OSAL_MBUF);
679    txmb = (IX_OSAL_MBUF *)p;
680
681    // initialize rx mbuf and give it to eth port
682    HAL_DCACHE_INVALIDATE(rxpkt, NPE_PKT_SIZE);
683    memset(rxmb, 0, sizeof(*rxmb));
684    IX_OSAL_MBUF_MDATA(rxmb) = (void *)rxpkt;
685    IX_OSAL_MBUF_MLEN(rxmb) = IX_OSAL_MBUF_PKT_LEN(rxmb) = NPE_PKT_SIZE;
686
687    ixEthAccPortRxFreeReplenish(portno, rxmb);
688
689    // register callbacks and enable eth port
690    ixEthAccPortRxCallbackRegister(portno, loop_rx_callback, 0);
691    ixEthAccPortTxDoneCallbackRegister(portno, loop_tx_callback, 0);
692
693    // clear flags
694    loop_txdone = loop_rxdone = loop_rxmatch = 0;
695   
696#ifdef DEBUG
697    diag_printf("check_phy_association: transmitting m[%x] data[%x] on port[%d] phy[%d]\n",
698                txmb, txpkt, portno, phyno);
699#endif
700
701    // transmit a packet
702    memset(txmb, 0, sizeof(*txmb));
703    IX_OSAL_MBUF_MDATA(txmb) = (void *)txpkt;
704    memset(txpkt, 0, NPE_PKT_SIZE);
705    txpkt[12] = 0x08;
706    txpkt[0] = portno;
707    txpkt[1] = phyno;
708    strcpy(txpkt + 14, "Hello");
709    IX_OSAL_MBUF_MLEN(txmb) = IX_OSAL_MBUF_PKT_LEN(txmb) = 100;
710    IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(txmb) = NULL;
711    HAL_DCACHE_FLUSH(IX_OSAL_MBUF_MDATA(txmb), IX_OSAL_MBUF_MLEN(txmb));
712    ixEthAccPortTxFrameSubmit(portno, txmb, IX_ETH_ACC_TX_DEFAULT_PRIORITY);
713    ixEthAccPortEnable(portno);
714
715    // wait for txdone
716    if (!__npe_poll_timed(portno, &loop_txdone, 100)) {
717#ifdef DEBUG
718        diag_printf("no txdone: eth[%d] phy[%d]\n", portno, phyno);
719#endif
720    } else if (!__npe_poll_timed(portno, &loop_rxmatch, 100)) {
721#ifdef DEBUG
722        diag_printf("no rxmatch: eth[%d] phy[%d] rxdone[%d]\n", portno, phyno, loop_rxdone);
723#endif
724    }
725
726    ixEthAccPortDisable(portno);
727
728    // Delay to give time for recovery of mbufs
729    for (i = 0; i < 100 && (!loop_txdone || !loop_rxdone); i++) {
730        __npe_poll(portno);
731        CYGACC_CALL_IF_DELAY_US((cyg_int32)1000);
732    }
733
734    ixEthMiiPhyLoopbackDisable(phyno);
735#ifdef DEBUG
736    diag_printf("check_phy_association: eth[%d] phy[%d] rxdone[%d] tx_done\n",
737                portno, phyno, loop_rxdone, loop_txdone);
738#endif
739
740    // return non-zero if packet looped back
741    return loop_rxmatch;
742}
743
744static void
745set_phy_association(int portno, int phyno)
746{
747#ifdef CYGSEM_INTEL_NPE_USE_ETH0
748    if (npe_eth0_priv_data.eth_id == portno) {
749        npe_eth0_priv_data.phy_no = phyno;
750        return;
751    }
752#endif
753#ifdef CYGSEM_INTEL_NPE_USE_ETH1
754    if (npe_eth1_priv_data.eth_id == portno) {
755        npe_eth1_priv_data.phy_no = phyno;
756        return;
757    }
758#endif
759#ifdef CYGSEM_INTEL_NPE_USE_ETH2
760    if (npe_eth2_priv_data.eth_id == portno) {
761        npe_eth2_priv_data.phy_no = phyno;
762        return;
763    }
764#endif
765}
766
767static void
768set_phy_mask(int portno, cyg_uint32 phymask)
769{
770#ifdef CYGSEM_INTEL_NPE_USE_ETH0
771    if (npe_eth0_priv_data.eth_id == portno) {
772        npe_eth0_priv_data.phy_mask = phymask;
773        return;
774    }
775#endif
776#ifdef CYGSEM_INTEL_NPE_USE_ETH1
777    if (npe_eth1_priv_data.eth_id == portno) {
778        npe_eth1_priv_data.phy_mask = phymask;
779        return;
780    }
781#endif
782#ifdef CYGSEM_INTEL_NPE_USE_ETH2
783    if (npe_eth2_priv_data.eth_id == portno) {
784        npe_eth2_priv_data.phy_mask = phymask;
785        return;
786    }
787#endif
788}
789#endif // CYGINT_DEVS_ETH_INTEL_NPE_PHY_DISCOVERY
790
791// Initialize given PHY
792// Returns non-zero if successful.
793static int
794phy_init(int phyno, BOOL autoneg, int timeout)
795{
796    ixEthMiiPhyReset(phyno);
797
798    ixEthMiiPhyConfig(phyno, TRUE, TRUE, autoneg);
799
800    // wait until the link is up before setting the MAC duplex
801    // mode, the PHY duplex mode may change after autonegotiation
802#if 0
803    link_check(phyno, timeout);
804#endif
805#ifdef DEBUG
806    diag_printf("\nPHY %d configuration:\n", phyno);
807    ixEthAccMiiShow(phyno);
808#endif
809
810    return 1;
811}
812
813// Initialize of a given group of PHYs
814// Returns phy_id is good link is found.
815//         NPE_PHY_UNKNOWN if timeout.
816static int
817phy_init_group(cyg_uint32 phy_mask, BOOL do_autoneg, int timeout)
818{
819    BOOL fullDuplex, linkUp, speed, autoneg;
820    int i;
821       
822#ifdef DEBUG
823    diag_printf("phy_init_group: mask[%08x] auto[%d] timeout[%d]\n",
824                phy_mask, do_autoneg, timeout);
825#endif
826
827    for (i = 0; i < IXP425_ETH_ACC_MII_MAX_ADDR; i++)
828        if ((phy_mask & (1 << i)) && phy_present(i)) {
829#ifdef DEBUG
830            diag_printf("phy_init_group: reset phy %d.\n", i);
831#endif
832            ixEthMiiPhyReset(i);
833            ixEthMiiPhyConfig(i, TRUE, TRUE, do_autoneg);
834            timeout -= 250;
835        }
836
837    linkUp = 0;
838    while (!linkUp && timeout > 0) {
839        for (i = 0; i < IXP425_ETH_ACC_MII_MAX_ADDR; i++)
840            if ((phy_mask & (1 << i)) && phy_present(i)) {
841                ixEthAccMiiLinkStatus(i, &linkUp, &speed, &fullDuplex, &autoneg);
842#ifdef DEBUG
843                diag_printf("phy_init_group: phy %d up[%d].\n", i, linkUp);
844#endif
845                if (linkUp)
846                    break;
847                timeout -= 200;
848            }
849        CYGACC_CALL_IF_DELAY_US((cyg_int32)100000);
850        timeout -= 100;
851    }
852    if (linkUp) {
853#ifdef DEBUG
854        diag_printf("phy_init_group: link found on PHY %d.\n", i);
855#endif
856        return i;
857    }
858
859#ifdef DEBUG
860    diag_printf("phy_init_group: all links down.\n");
861#endif
862
863    /* settle for first PHY in group */
864    for (i = 0; i < IXP425_ETH_ACC_MII_MAX_ADDR; i++)
865        if ((phy_mask & (1 << i)) && phy_present(i))
866                return i;
867
868    return NPE_PHY_UNKNOWN;
869}
870
871// Initialize given MAC based on given PHY
872// Returns non-zero if successful.
873static int
874mac_init(int portno, int phyno)
875{
876    BOOL speed, linkUp, fullDuplex, autoneg;
877
878    ixEthAccMiiLinkStatus(phyno, &linkUp, &speed, &fullDuplex, &autoneg);
879
880    /* Set the MAC duplex mode */
881    if (ixEthAccPortDuplexModeSet(portno, fullDuplex ? IX_ETH_ACC_FULL_DUPLEX :
882                                  IX_ETH_ACC_HALF_DUPLEX) != IX_ETH_ACC_SUCCESS) {
883        diag_printf("PortDuplexModeSet:  failed!\n");
884        return 0;
885    }
886    return 1;
887}
888
889// ethAcc RX callback
890static void
891npe_rx_callback(cyg_uint32 cbTag, IX_OSAL_MBUF *m, IxEthAccPortId portid)
892{
893    struct npe* p_npe = (struct npe *)cbTag;
894    struct eth_drv_sc *sc;
895
896#ifdef DEBUG
897    diag_printf("npe_rx_callback: m[%x] data[%x] len[%x]\n",
898                m, IX_OSAL_MBUF_MDATA(m), IX_OSAL_MBUF_MLEN(m));
899#endif
900
901    sc = p_npe->sc;
902
903    if (IX_OSAL_MBUF_MDATA(m) == 0)
904        return;
905
906    if (IX_OSAL_MBUF_MLEN(m) > 0) {
907        mbuf_enqueue(&p_npe->rxQHead, m);
908
909        (sc->funs->eth_drv->recv)(sc, IX_OSAL_MBUF_MLEN(m));
910    }
911
912    // Now return mbuf to NPE
913    IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE;
914    IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(m) = NULL;
915    IX_OSAL_MBUF_FLAGS(m) = 0;
916   
917    HAL_DCACHE_INVALIDATE(IX_OSAL_MBUF_MDATA(m), NPE_PKT_SIZE);
918 
919    if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) {
920#ifdef DEBUG
921        diag_printf("npe_rx_callback: Error returning mbuf.\n");
922#endif
923    }
924}
925
926// callback which is used by ethAcc to recover RX buffers when stopping
927static void
928npe_rx_stop_callback(cyg_uint32 cbTag, IX_OSAL_MBUF *m, IxEthAccPortId portid)
929{
930}
931
932
933// ethAcc TX callback
934static void
935npe_tx_callback(cyg_uint32 cbTag, IX_OSAL_MBUF *m)
936{
937    struct npe* p_npe = (struct npe *)cbTag;
938    struct eth_drv_sc *sc;
939
940#ifdef DEBUG
941    diag_printf("npe_tx_callback: m[%x] data[%x] len[%x]\n",
942                m, IX_OSAL_MBUF_MDATA(m), IX_OSAL_MBUF_MLEN(m));
943#endif
944
945    sc = p_npe->sc;
946
947    (sc->funs->eth_drv->tx_done)(sc, (unsigned long)IX_OSAL_MBUF_PRIV(m), 1);
948   
949    IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE;
950    IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(m) = NULL;
951    IX_OSAL_MBUF_FLAGS(m) = 0;
952
953    mbuf_enqueue(&p_npe->txQHead, m);
954}
955
956
957// callback which is used by ethAcc to recover TX buffers when stopping
958static void
959npe_tx_stop_callback(cyg_uint32 cbTag, IX_OSAL_MBUF *m)
960{
961}
962
963static int
964npe_set_mac_address(struct npe *p_npe)
965{
966    int mac_ok = false;
967    IxEthAccMacAddr  npeMac;
968
969    // Set MAC address
970#if defined(CYGPKG_DEVS_ETH_INTEL_NPE_REDBOOT_HOLDS_ESA)
971    {
972        char *cfgname = NULL;
973#if defined(CYGSEM_INTEL_NPE_USE_ETH0)
974        if (p_npe == &npe_eth0_priv_data)
975            cfgname = "npe_" CYGDAT_NPE_ETH0_NAME "_esa";
976#endif
977#if defined(CYGSEM_INTEL_NPE_USE_ETH1)
978        if (p_npe == &npe_eth1_priv_data)
979            cfgname = "npe_" CYGDAT_NPE_ETH1_NAME "_esa";
980#endif
981#if defined(CYGSEM_INTEL_NPE_USE_ETH2)
982        if (p_npe == &npe_eth2_priv_data)
983            cfgname = "npe_" CYGDAT_NPE_ETH2_NAME "_esa";
984#endif
985        mac_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET, cfgname,
986                                             p_npe->mac_address, CONFIG_ESA);
987    }
988#elif defined(CYGHAL_GET_NPE_ESA)
989    CYGHAL_GET_NPE_ESA(p_npe->eth_id, p_npe->mac_address, mac_ok);
990#else
991#error No mechanism to get MAC address
992#endif
993
994    if (!mac_ok) {
995#ifdef DEBUG
996        diag_printf("Error getting MAC address for %s.\n", npe_names[p_npe->eth_id]);
997#endif
998        return 0;
999    }
1000
1001    npeMac.macAddress[0] = p_npe->mac_address[0];
1002    npeMac.macAddress[1] = p_npe->mac_address[1];
1003    npeMac.macAddress[2] = p_npe->mac_address[2];
1004    npeMac.macAddress[3] = p_npe->mac_address[3];
1005    npeMac.macAddress[4] = p_npe->mac_address[4];
1006    npeMac.macAddress[5] = p_npe->mac_address[5];
1007
1008    if (ixEthAccPortUnicastMacAddressSet(p_npe->eth_id, &npeMac) != IX_ETH_ACC_SUCCESS) {
1009        diag_printf("Error setting unicast address! %02x:%02x:%02x:%02x:%02x:%02x\n",
1010                    npeMac.macAddress[0], npeMac.macAddress[1],
1011                    npeMac.macAddress[2], npeMac.macAddress[3],
1012                    npeMac.macAddress[4], npeMac.macAddress[5]);
1013        return 0;
1014    }
1015    return 1;
1016}
1017
1018
1019// Boot-time CSR library initialization.
1020static int
1021npe_csr_load(void)
1022{
1023    int i;
1024
1025#ifdef DEBUG
1026    diag_printf("\nnpe_csr_load\n");
1027#endif
1028
1029#ifdef __NPEA_HSS_COEXIST
1030#define NPEA_IMAGE IX_NPEDL_NPEIMAGE_NPEA_ETH_MACFILTERLEARN_HSSCHAN_COEXIST
1031#else
1032#define NPEA_IMAGE IX_NPEDL_NPEIMAGE_NPEA_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS
1033#endif
1034#define NPEB_IMAGE IX_NPEDL_NPEIMAGE_NPEB_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS
1035#define NPEC_IMAGE IX_NPEDL_NPEIMAGE_NPEC_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS
1036
1037    if (ixQMgrInit() != IX_SUCCESS) {
1038        diag_printf("Error initialising queue manager!\n");
1039        return 0;
1040    }
1041
1042    ixQMgrDispatcherLoopGet(&qDispatcherFunc);
1043
1044    if(ixNpeMhInitialize(IX_NPEMH_NPEINTERRUPTS_YES) != IX_SUCCESS) {
1045        diag_printf("Error initialising NPE Message handler!\n");
1046        return 0;
1047    }
1048
1049    if (npe_used[IX_ETH_PORT_1] && npe_exists[IX_ETH_PORT_1] &&
1050        ixNpeDlNpeInitAndStart(NPEB_IMAGE) != IX_SUCCESS) {
1051        diag_printf("Error downloading firmware to NPE-B!\n");
1052        return 0;
1053    }
1054
1055    if (npe_used[IX_ETH_PORT_2] && npe_exists[IX_ETH_PORT_2] &&
1056        ixNpeDlNpeInitAndStart(NPEC_IMAGE) != IX_SUCCESS) {
1057        diag_printf("Error downloading firmware to NPE-C!\n");
1058        return 0;
1059    }
1060
1061    if (npe_used[IX_ETH_PORT_3] && npe_exists[IX_ETH_PORT_3] &&
1062        ixNpeDlNpeInitAndStart(NPEA_IMAGE) != IX_SUCCESS) {
1063        diag_printf("Error downloading firmware to NPE-A!\n");
1064        return 0;
1065    }
1066
1067#ifdef CYGPKG_REDBOOT
1068    // don't need this for redboot
1069    ixFeatureCtrlSwConfigurationWrite(IX_FEATURECTRL_ETH_LEARNING, FALSE);
1070#endif
1071
1072    if (ixEthAccInit() != IX_ETH_ACC_SUCCESS) {
1073        diag_printf("Error initialising Ethernet access driver!\n");
1074        return 0;
1075    }
1076
1077    for (i = 0; i < IX_ETH_ACC_NUMBER_OF_PORTS; i++) {
1078        if (!npe_used[i] || !npe_exists[i])
1079            continue;
1080        if (ixEthAccPortInit(i) != IX_ETH_ACC_SUCCESS) {
1081            diag_printf("Error initialising Ethernet port%d!\n", i);
1082        }
1083        if (ixEthAccTxSchedulingDisciplineSet(i, FIFO_NO_PRIORITY) != IX_ETH_ACC_SUCCESS) {
1084            diag_printf("Error setting scheduling discipline for port %d.\n", i);
1085        }
1086        if (ixEthAccPortRxFrameAppendFCSDisable(i) != IX_ETH_ACC_SUCCESS) {
1087            diag_printf("Error disabling RX FCS for port %d.\n", i);
1088        }
1089        if (ixEthAccPortTxFrameAppendFCSEnable(i) != IX_ETH_ACC_SUCCESS) {
1090            diag_printf("Error enabling TX FCS for port %d.\n", i);
1091        }
1092    }
1093
1094#if defined(CYGSEM_INTEL_NPE_USE_ETH0)
1095    if (npe_exists[npe_eth0_priv_data.eth_id])
1096        npe_set_mac_address(&npe_eth0_priv_data);
1097#endif
1098#if defined(CYGSEM_INTEL_NPE_USE_ETH1)
1099    if (npe_exists[npe_eth1_priv_data.eth_id])
1100        npe_set_mac_address(&npe_eth1_priv_data);
1101#endif
1102#if defined(CYGSEM_INTEL_NPE_USE_ETH2)
1103    if (npe_exists[npe_eth2_priv_data.eth_id])
1104        npe_set_mac_address(&npe_eth2_priv_data);
1105#endif
1106
1107    memset(phy_scanned, 0, sizeof(phy_scanned));
1108    memset(phy_inited, 0, sizeof(phy_inited));
1109
1110    return 1;
1111}
1112
1113#if CYGINT_DEVS_ETH_INTEL_NPE_PHY_DISCOVERY
1114// Uninitialize CSR library.
1115static void
1116npe_csr_unload(void)
1117{
1118#ifdef DEBUG
1119    diag_printf("\nnpe_csr_unload\n");
1120#endif
1121    ixEthAccUninit();
1122    ixEthDBUnload();
1123    ixNpeMhUnload();
1124    ixQMgrUnload();
1125}
1126#endif
1127
1128// ------------------------------------------------------------------------
1129//
1130//  API Function : npe_init
1131//
1132// ------------------------------------------------------------------------
1133static bool
1134npe_init(struct cyg_netdevtab_entry * ndp)
1135{
1136    static int initialized = 0;
1137    struct eth_drv_sc *sc;
1138    struct npe *p_npe;
1139    int i;
1140
1141    sc = (struct eth_drv_sc *)ndp->device_instance;
1142    p_npe = (struct npe *)sc->driver_private;
1143
1144    p_npe->sc = sc;
1145
1146    if (!initialized) {
1147        // One time initialization common to all ports
1148        initialized = 1;
1149
1150        switch(ixFeatureCtrlDeviceRead()) {
1151
1152        case IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X:
1153            switch (ixFeatureCtrlProductIdRead() & IX_FEATURE_CTRL_SILICON_STEPPING_MASK) {
1154            case IX_FEATURE_CTRL_SILICON_TYPE_B0:
1155                /*
1156                 * If it is B0 Silicon, we only enable port when its corresponding 
1157                 * Eth Coprocessor is available.
1158                 */
1159                if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) ==
1160                    IX_FEATURE_CTRL_COMPONENT_ENABLED)
1161                    npe_exists[IX_ETH_PORT_1] = TRUE;
1162
1163                if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) == 
1164                    IX_FEATURE_CTRL_COMPONENT_ENABLED)
1165                    npe_exists[IX_ETH_PORT_2] = TRUE;
1166                break;
1167            case IX_FEATURE_CTRL_SILICON_TYPE_A0:
1168                /*
1169                 * If it is A0 Silicon, we enable both as both Eth Coprocessors
1170                 * are available.
1171                 */ 
1172                npe_exists[IX_ETH_PORT_1] = TRUE;
1173                npe_exists[IX_ETH_PORT_2] = TRUE;
1174                break;
1175            }
1176            break;
1177        case IX_FEATURE_CTRL_DEVICE_TYPE_IXP46X:
1178            if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) == IX_FEATURE_CTRL_COMPONENT_ENABLED)
1179                npe_exists[IX_ETH_PORT_1] = TRUE;
1180            /* fall through */
1181        case IX_FEATURE_CTRL_DEVICE_TYPE_IXP43X:
1182            if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) == IX_FEATURE_CTRL_COMPONENT_ENABLED)
1183                npe_exists[IX_ETH_PORT_2] = TRUE;
1184
1185            if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_NPEA_ETH) == IX_FEATURE_CTRL_COMPONENT_ENABLED)
1186                npe_exists[IX_ETH_PORT_3] = utopia_enabled() ? FALSE : TRUE;
1187            break;
1188        default:
1189            diag_printf("npe_init: Unknown Device: 0x%x\n", ixFeatureCtrlDeviceRead());
1190        }
1191
1192#if defined(CYGSEM_INTEL_NPE_USE_ETH0)
1193        npe_used[CYGNUM_ETH0_ETH_ID] = 1;
1194#endif
1195#if defined(CYGSEM_INTEL_NPE_USE_ETH1)
1196        npe_used[CYGNUM_ETH1_ETH_ID] = 1;
1197#endif
1198#if defined(CYGSEM_INTEL_NPE_USE_ETH2)
1199        npe_used[CYGNUM_ETH2_ETH_ID] = 1;
1200#endif
1201
1202#ifndef __NPEA_HSS_COEXIST
1203        // If we need NPE-A for ethernet, turn off Utopia
1204        if (npe_used[IX_ETH_PORT_3] && npe_exists[IX_ETH_PORT_3])
1205            ixFeatureCtrlWrite(ixFeatureCtrlRead() | (1 << IX_FEATURECTRL_UTOPIA));
1206#endif
1207
1208        npe_alloc_end = npe_alloc_pool + sizeof(npe_alloc_pool);
1209        npe_alloc_free = (cyg_uint8 *)(((unsigned)npe_alloc_pool + HAL_DCACHE_LINE_SIZE - 1)
1210                                       & ~(HAL_DCACHE_LINE_SIZE - 1));
1211
1212#if defined(CYGSEM_NPE_SMII)
1213#if !defined(CYGHAL_NPE_SMII_INIT)
1214#define CYGHAL_NPE_SMII_INIT() do_enable_smii_mode()
1215#endif
1216        if (!CYGHAL_NPE_SMII_INIT()) {
1217            diag_printf("NPE SMII initialization failed!\n");
1218            return 0;
1219        }
1220#endif
1221
1222        if (!npe_csr_load())
1223            return 0;
1224
1225        diag_printf("\n");
1226    }
1227
1228    if (!npe_exists[p_npe->eth_id])
1229        return 0;
1230
1231    diag_printf("Trying %s...", npe_names[p_npe->eth_id]);
1232
1233#if CYGINT_DEVS_ETH_INTEL_NPE_PHY_DISCOVERY
1234    // This tries to find which phy (could be more than one) is
1235    // connected to this port.
1236    if (p_npe->phy_no == NPE_PHY_UNKNOWN) {
1237        for (i = 0; i < IXP425_ETH_ACC_MII_MAX_ADDR; i++) {
1238            if (!(p_npe->phy_mask & (1 << i)))
1239                continue;
1240            // if this is only possible PHY, then go with it...
1241            if (!(p_npe->phy_mask & ~(1 << i))) {
1242                set_phy_association(p_npe->eth_id, i);
1243                break;
1244            }
1245            if (check_phy_association(p_npe->eth_id, i)) {
1246                set_phy_association(p_npe->eth_id, i);
1247                break;
1248            }
1249        }
1250    }
1251#endif
1252    if (p_npe->phy_no == NPE_PHY_GROUP) {
1253        p_npe->phy_no = phy_init_group(p_npe->phy_mask, TRUE, 5000);
1254        if (p_npe->phy_no == NPE_PHY_UNKNOWN) {
1255            diag_printf("no PHY found\n");
1256            return 0;
1257        }
1258    } else {
1259        if (p_npe->phy_no == NPE_PHY_UNKNOWN || !phy_present(p_npe->phy_no)) {
1260            diag_printf("no PHY found\n");
1261            return 0;
1262        }
1263 
1264        if (!phy_init(p_npe->phy_no, TRUE, 2000)) {
1265            diag_printf("PHY init error!\n");
1266            return 0;
1267        }
1268    }
1269
1270#ifdef DEBUG
1271    diag_printf("phy for %s found!\n", npe_names[p_npe->eth_id]);
1272#endif
1273
1274    if (!mac_init(p_npe->eth_id, p_npe->phy_no)) {
1275        diag_printf("MAC init error!\n");
1276        return 0;
1277    }
1278
1279    // initialize mbuf pool
1280    init_rx_mbufs(p_npe);
1281    init_tx_mbufs(p_npe);
1282
1283    if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_callback,
1284                                       (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
1285        diag_printf("can't register RX callback!\n");
1286        return 0;
1287    }
1288
1289    if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_callback,
1290                                           (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
1291        diag_printf("can't register TX callback!\n");
1292        return 0;
1293    }
1294
1295    if (ixEthAccPortEnable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
1296        diag_printf("can't enable port!\n");
1297        return 0;
1298    }
1299
1300    p_npe->active = 1;
1301
1302    diag_printf("success. Using %s with PHY %d.\n",
1303                npe_names[p_npe->eth_id], p_npe->phy_no);
1304
1305    // Initialize upper level driver
1306    (sc->funs->eth_drv->init)(sc, &(p_npe->mac_address[0]) );
1307
1308    return 1;
1309}
1310
1311// ------------------------------------------------------------------------
1312//
1313//  API Function : npe_start
1314//
1315// ------------------------------------------------------------------------
1316static void 
1317npe_start( struct eth_drv_sc *sc, unsigned char *enaddr, int flags )
1318{
1319#ifndef CYGPKG_REDBOOT
1320    struct npe *p_npe = (struct npe *)sc->driver_private;
1321
1322    if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_callback,
1323                                       (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
1324#ifdef DEBUG
1325        diag_printf("Error registering rx callback!\n");
1326#endif
1327    }
1328
1329    if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_callback,
1330                                           (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
1331#ifdef DEBUG
1332        diag_printf("Error registering tx callback!\n");
1333#endif
1334    }
1335
1336    if (ixEthAccPortEnable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
1337#ifdef DEBUG
1338        diag_printf("npe_start: Error disabling %s!\n", npe_names[p_npe->eth_id]);
1339#endif
1340    }
1341
1342    p_npe->active = 1;
1343#endif
1344}
1345
1346// ------------------------------------------------------------------------
1347//
1348//  API Function : npe_stop
1349//
1350// ------------------------------------------------------------------------
1351static void
1352npe_stop( struct eth_drv_sc *sc )
1353{
1354    struct npe *p_npe = (struct npe *)sc->driver_private;
1355    int i;
1356
1357    if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_stop_callback,
1358                                       (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
1359#ifdef DEBUG
1360        diag_printf("Error registering rx callback!\n");
1361#endif
1362    }
1363
1364    if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_stop_callback,
1365                                           (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
1366#ifdef DEBUG
1367        diag_printf("Error registering tx callback!\n");
1368#endif
1369    }
1370
1371    if (ixEthAccPortDisable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
1372#ifdef DEBUG
1373        diag_printf("npe_stop: Error disabling NPE!\n");
1374#endif
1375    }
1376
1377    // Delay to give time for recovery of mbufs
1378    for (i = 0; i < 100; i++) {
1379        CYGACC_CALL_IF_DELAY_US((cyg_int32)10000);
1380        __npe_poll(p_npe->eth_id);
1381    }
1382
1383// For RedBoot only, we are probably launching Linux or other OS that
1384// needs a clean slate for its NPE library.     
1385#ifdef CYGPKG_REDBOOT
1386    for (i = 0; i < IX_ETH_ACC_NUMBER_OF_PORTS; i++) {
1387        if (npe_used[i] && npe_exists[i])
1388            if (ixNpeDlNpeStopAndReset(__eth_to_npe(i)) != IX_SUCCESS)
1389                diag_printf ("Failed to stop and reset eth%d.\n", i);
1390    }
1391#endif
1392    p_npe->active = 0;
1393}
1394
1395
1396// ------------------------------------------------------------------------
1397//
1398//  API Function : npe_recv
1399//
1400// ------------------------------------------------------------------------
1401static void 
1402npe_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len )
1403{
1404    struct npe *p_npe = (struct npe *)sc->driver_private;
1405    struct eth_drv_sg *sg = sg_list;
1406    IX_OSAL_MBUF *m;
1407    cyg_uint8 *src;
1408    unsigned len;
1409
1410    m = mbuf_dequeue(&p_npe->rxQHead);
1411    src = IX_OSAL_MBUF_MDATA(m);
1412
1413    while (sg < &sg_list[sg_len]) {
1414           
1415        len = sg->len;
1416
1417        if (len < 0 || sg->buf == 0)
1418            return;
1419
1420        if (len > IX_OSAL_MBUF_MLEN(m))
1421            len = IX_OSAL_MBUF_MLEN(m);
1422
1423        memcpy((char *)sg->buf, src, len);
1424        src += len;
1425        IX_OSAL_MBUF_MLEN(m) -= len;
1426
1427        ++sg;
1428    }
1429}
1430
1431// ------------------------------------------------------------------------
1432//
1433//  API Function : npe_can_send
1434//
1435// ------------------------------------------------------------------------
1436static int 
1437npe_can_send(struct eth_drv_sc *sc)
1438{
1439    struct npe *p_npe = (struct npe *)sc->driver_private;
1440
1441    return p_npe->active && p_npe->txQHead != NULL;
1442}
1443
1444// ------------------------------------------------------------------------
1445//
1446//  API Function : npe_send
1447//
1448// ------------------------------------------------------------------------
1449static void 
1450npe_send(struct eth_drv_sc *sc,
1451         struct eth_drv_sg *sg_list, int sg_len,
1452         int total_len, unsigned long key)
1453{
1454    struct npe *p_npe = (struct npe *)sc->driver_private;
1455    struct eth_drv_sg *sg = sg_list;
1456    cyg_uint8 *dest;
1457    int len, err;
1458    IX_OSAL_MBUF *m;
1459
1460    m = mbuf_dequeue(&p_npe->txQHead);
1461
1462    dest = IX_OSAL_MBUF_MDATA(m);
1463    if ((unsigned)total_len > IX_OSAL_MBUF_MLEN(m))
1464        total_len = IX_OSAL_MBUF_MLEN(m);
1465
1466    IX_OSAL_MBUF_PKT_LEN(m) = IX_OSAL_MBUF_MLEN(m) = total_len;
1467    IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m) = NULL;
1468    IX_OSAL_MBUF_PRIV(m) = (void *)key;
1469
1470#ifdef DEBUG
1471    diag_printf("npe_send: m[%x] data[%x] len[%d]\n", m, dest, total_len);
1472#endif
1473
1474    while (sg < &sg_list[sg_len] && total_len > 0) {
1475
1476        len = sg->len;
1477        if (len > total_len)
1478            len = total_len;
1479
1480        memcpy(dest, (char *)sg->buf, len);
1481
1482        dest += len;
1483        total_len -= len;
1484
1485        ++sg;
1486    }
1487
1488    HAL_DCACHE_FLUSH(IX_OSAL_MBUF_MDATA(m), IX_OSAL_MBUF_MLEN(m));
1489
1490    if ((err = ixEthAccPortTxFrameSubmit(p_npe->eth_id, m, IX_ETH_ACC_TX_DEFAULT_PRIORITY))
1491       != IX_ETH_ACC_SUCCESS) {
1492#ifdef DEBUG
1493        diag_printf("npe_send: Can't submit frame. err[%d]\n", err);
1494#endif
1495        mbuf_enqueue(&p_npe->txQHead, m);
1496        return;
1497    }
1498}
1499
1500// ------------------------------------------------------------------------
1501//
1502//  API Function : npe_deliver
1503//
1504// ------------------------------------------------------------------------
1505static void
1506npe_deliver(struct eth_drv_sc *sc)
1507{
1508}
1509
1510// ------------------------------------------------------------------------
1511//
1512//  API Function : npe_poll
1513//
1514// ------------------------------------------------------------------------
1515static void
1516npe_poll(struct eth_drv_sc *sc)
1517{
1518    struct npe *p_npe = (struct npe *)sc->driver_private;
1519    cyg_uint32 ints;
1520
1521    ints = *IXP425_INTR_EN;
1522    *IXP425_INTR_EN = ints & ~NPE_INT_BITS;
1523
1524    __npe_poll(p_npe->eth_id);
1525
1526    *IXP425_INTR_EN = ints;
1527}
1528
1529
1530// ------------------------------------------------------------------------
1531//
1532//  API Function : npe_int_vector
1533//
1534// ------------------------------------------------------------------------
1535static int
1536npe_int_vector(struct eth_drv_sc *sc)
1537{
1538    struct npe *p_npe;
1539    p_npe = (struct npe *)sc->driver_private;
1540
1541    if (p_npe->eth_id == IX_ETH_PORT_1)
1542        return CYGNUM_HAL_INTERRUPT_NPEB;
1543    else if (p_npe->eth_id == IX_ETH_PORT_2)
1544        return CYGNUM_HAL_INTERRUPT_NPEC;
1545    else if (p_npe->eth_id == IX_ETH_PORT_3)
1546        return CYGNUM_HAL_INTERRUPT_NPEA;
1547    return -1;
1548}
1549
1550
1551// ------------------------------------------------------------------------
1552//
1553//  API Function : npe_ioctl
1554//
1555// ------------------------------------------------------------------------
1556static int
1557npe_ioctl(struct eth_drv_sc *sc, unsigned long key,
1558          void *data, int data_length)
1559{
1560    return -1;
1561}
1562
1563
1564#ifdef CYGSEM_INTEL_NPE_USE_ETH0
1565ETH_DRV_SC(npe_sc0,
1566           &npe_eth0_priv_data,
1567           CYGDAT_NPE_ETH0_NAME,
1568           npe_start,
1569           npe_stop,
1570           npe_ioctl,
1571           npe_can_send,
1572           npe_send,
1573           npe_recv,
1574           npe_deliver,
1575           npe_poll,
1576           npe_int_vector);
1577
1578NETDEVTAB_ENTRY(npe_netdev0, 
1579                "npe_" CYGDAT_NPE_ETH0_NAME,
1580                npe_init, 
1581                &npe_sc0);
1582#endif // CYGSEM_INTEL_NPE_USE_ETH0
1583
1584#ifdef CYGSEM_INTEL_NPE_USE_ETH1
1585ETH_DRV_SC(npe_sc1,
1586           &npe_eth1_priv_data,
1587           CYGDAT_NPE_ETH1_NAME,
1588           npe_start,
1589           npe_stop,
1590           npe_ioctl,
1591           npe_can_send,
1592           npe_send,
1593           npe_recv,
1594           npe_deliver,
1595           npe_poll,
1596           npe_int_vector);
1597
1598NETDEVTAB_ENTRY(npe_netdev1, 
1599                "npe_" CYGDAT_NPE_ETH1_NAME,
1600                npe_init, 
1601                &npe_sc1);
1602#endif // CYGSEM_INTEL_NPE_USE_ETH1
1603
1604#ifdef CYGSEM_INTEL_NPE_USE_ETH2
1605ETH_DRV_SC(npe_sc2,
1606           &npe_eth2_priv_data,
1607           CYGDAT_NPE_ETH2_NAME,
1608           npe_start,
1609           npe_stop,
1610           npe_ioctl,
1611           npe_can_send,
1612           npe_send,
1613           npe_recv,
1614           npe_deliver,
1615           npe_poll,
1616           npe_int_vector);
1617
1618NETDEVTAB_ENTRY(npe_netdev2, 
1619                "npe_" CYGDAT_NPE_ETH2_NAME,
1620                npe_init, 
1621                &npe_sc2);
1622#endif // CYGSEM_INTEL_NPE_USE_ETH1
1623
1624// ------------------------------------------------------------------------
1625// EOF if_npe.c
Note: See TracBrowser for help on using the repository browser.