aboutsummaryrefslogtreecommitdiff
path: root/sys/mips/rmi/dev/xlr/rge.c
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2010-01-10 05:11:27 +0000
committerWarner Losh <imp@FreeBSD.org>2010-01-10 05:11:27 +0000
commit8cc6cc81dd69284d9d0d2ec136605db17f7184a0 (patch)
tree602ace12e800e9d026e523bde3d9e1496adfa270 /sys/mips/rmi/dev/xlr/rge.c
parent522e41fcac3937e5a08a2453849e4c09f52a3972 (diff)
parent9311b216396b24429a24861e943efde7f3776c1d (diff)
downloadsrc-8cc6cc81dd69284d9d0d2ec136605db17f7184a0.tar.gz
src-8cc6cc81dd69284d9d0d2ec136605db17f7184a0.zip
Merge from projects/mips to head by hand:
Copy sys/dev/rmi to sys/mips/rmi/dev [sic]. For devices that are on only one SoC, or family of SoC, we place them under sys/<vendor>/dev. I'll fix the build problems this causes as best I can since rmi kernel require external toolchains due to lack of support for rmi op-codes in the ancient binutils we have in the tree.
Notes
Notes: svn path=/head/; revision=201979
Diffstat (limited to 'sys/mips/rmi/dev/xlr/rge.c')
-rw-r--r--sys/mips/rmi/dev/xlr/rge.c2748
1 files changed, 2748 insertions, 0 deletions
diff --git a/sys/mips/rmi/dev/xlr/rge.c b/sys/mips/rmi/dev/xlr/rge.c
new file mode 100644
index 000000000000..e0fa8c15851a
--- /dev/null
+++ b/sys/mips/rmi/dev/xlr/rge.c
@@ -0,0 +1,2748 @@
+/*-
+ * Copyright (c) 2003-2009 RMI Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of RMI Corporation, nor the names of its contributors,
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * RMI_BSD */
+
+#ifdef HAVE_KERNEL_OPTION_HEADERS
+#include "opt_device_polling.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/limits.h>
+#include <sys/bus.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#define __RMAN_RESOURCE_VISIBLE
+#include <sys/rman.h>
+#include <sys/taskqueue.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/reg.h>
+#include <machine/cpu.h>
+#include <machine/mips_opcode.h>
+#include <machine/asm.h>
+#include <mips/rmi/rmi_mips_exts.h>
+#include <machine/cpuregs.h>
+
+#include <machine/param.h>
+#include <machine/intr_machdep.h>
+#include <machine/clock.h> /* for DELAY */
+#include <machine/bus.h> /* */
+#include <machine/resource.h>
+#include <mips/rmi/interrupt.h>
+#include <mips/rmi/msgring.h>
+#include <mips/rmi/iomap.h>
+#include <mips/rmi/debug.h>
+#include <mips/rmi/pic.h>
+#include <mips/rmi/xlrconfig.h>
+#include <mips/rmi/shared_structs.h>
+#include <mips/rmi/board.h>
+
+#include <dev/rmi/xlr/atx_cpld.h>
+#include <dev/rmi/xlr/xgmac_mdio.h>
+
+
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/brgphyreg.h>
+
+#include <sys/sysctl.h>
+#include <dev/rmi/xlr/rge.h>
+
+/* #include "opt_rge.h" */
+
+#include "miibus_if.h"
+
+MODULE_DEPEND(rge, ether, 1, 1, 1);
+MODULE_DEPEND(rge, miibus, 1, 1, 1);
+
+/* #define DEBUG */
+/*#define RX_COPY */
+
+#define RGE_TX_THRESHOLD 1024
+#define RGE_TX_Q_SIZE 1024
+
+#ifdef DEBUG
+#undef dbg_msg
+int mac_debug = 1;
+
+#define dbg_msg(fmt, args...) \
+ do {\
+ if (mac_debug) {\
+ printf("[%s@%d|%s]: cpu_%d: " fmt, \
+ __FILE__, __LINE__, __FUNCTION__, PCPU_GET(cpuid), ##args);\
+ }\
+ } while(0);
+
+#define DUMP_PACKETS
+#else
+#undef dbg_msg
+#define dbg_msg(fmt, args...)
+int mac_debug = 0;
+
+#endif
+
+#define MAC_B2B_IPG 88
+
+/* frame sizes need to be cacheline aligned */
+#define MAX_FRAME_SIZE 1536
+#define MAX_FRAME_SIZE_JUMBO 9216
+
+#define MAC_SKB_BACK_PTR_SIZE SMP_CACHE_BYTES
+#define MAC_PREPAD 0
+#define BYTE_OFFSET 2
+#define XLR_RX_BUF_SIZE (MAX_FRAME_SIZE+BYTE_OFFSET+MAC_PREPAD+MAC_SKB_BACK_PTR_SIZE+SMP_CACHE_BYTES)
+#define MAC_CRC_LEN 4
+#define MAX_NUM_MSGRNG_STN_CC 128
+
+#define MAX_NUM_DESC 1024
+#define MAX_SPILL_SIZE (MAX_NUM_DESC + 128)
+
+#define MAC_FRIN_TO_BE_SENT_THRESHOLD 16
+
+#define MAX_FRIN_SPILL (MAX_SPILL_SIZE << 2)
+#define MAX_FROUT_SPILL (MAX_SPILL_SIZE << 2)
+#define MAX_CLASS_0_SPILL (MAX_SPILL_SIZE << 2)
+#define MAX_CLASS_1_SPILL (MAX_SPILL_SIZE << 2)
+#define MAX_CLASS_2_SPILL (MAX_SPILL_SIZE << 2)
+#define MAX_CLASS_3_SPILL (MAX_SPILL_SIZE << 2)
+
+/*****************************************************************
+ * Phoenix Generic Mac driver
+ *****************************************************************/
+
+extern uint32_t cpu_ltop_map[32];
+
+#ifdef ENABLED_DEBUG
+static int port_counters[4][8] __aligned(XLR_CACHELINE_SIZE);
+
+#define port_inc_counter(port, counter) atomic_add_int(&port_counters[port][(counter)], 1)
+#define port_set_counter(port, counter, value) atomic_set_int(&port_counters[port][(counter)], (value))
+#else
+#define port_inc_counter(port, counter) /* Nothing */
+#define port_set_counter(port, counter, value) /* Nothing */
+#endif
+
+int xlr_rge_tx_prepend[MAXCPU];
+int xlr_rge_tx_done[MAXCPU];
+int xlr_rge_get_p2d_failed[MAXCPU];
+int xlr_rge_msg_snd_failed[MAXCPU];
+int xlr_rge_tx_ok_done[MAXCPU];
+int xlr_rge_rx_done[MAXCPU];
+int xlr_rge_repl_done[MAXCPU];
+
+static __inline__ unsigned int
+ldadd_wu(unsigned int value, unsigned long *addr)
+{
+ __asm__ __volatile__(".set push\n"
+ ".set noreorder\n"
+ "move $8, %2\n"
+ "move $9, %3\n"
+ /* "ldaddwu $8, $9\n" */
+ ".word 0x71280011\n"
+ "move %0, $8\n"
+ ".set pop\n"
+ : "=&r"(value), "+m"(*addr)
+ : "0"(value), "r"((unsigned long)addr)
+ : "$8", "$9");
+
+ return value;
+}
+
+/* #define mac_stats_add(x, val) ({(x) += (val);}) */
+#define mac_stats_add(x, val) ldadd_wu(val, &x)
+
+
+#define XLR_MAX_CORE 8
+#define RGE_LOCK_INIT(_sc, _name) \
+ mtx_init(&(_sc)->rge_mtx, _name, MTX_NETWORK_LOCK, MTX_DEF)
+#define RGE_LOCK(_sc) mtx_lock(&(_sc)->rge_mtx)
+#define RGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->rge_mtx, MA_OWNED)
+#define RGE_UNLOCK(_sc) mtx_unlock(&(_sc)->rge_mtx)
+#define RGE_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->rge_mtx)
+
+#define XLR_MAX_MACS 8
+#define XLR_MAX_TX_FRAGS 14
+#define MAX_P2D_DESC_PER_PORT 512
+struct p2d_tx_desc {
+ uint64_t frag[XLR_MAX_TX_FRAGS + 2];
+};
+
+#define MAX_TX_RING_SIZE (XLR_MAX_MACS * MAX_P2D_DESC_PER_PORT * sizeof(struct p2d_tx_desc))
+
+struct rge_softc *dev_mac[XLR_MAX_MACS];
+static int dev_mac_xgs0;
+static int dev_mac_gmac0;
+
+static int gmac_common_init_done;
+
+
+static int rge_probe(device_t);
+static int rge_attach(device_t);
+static int rge_detach(device_t);
+static int rge_suspend(device_t);
+static int rge_resume(device_t);
+static void rge_release_resources(struct rge_softc *);
+static void rge_rx(struct rge_softc *, vm_paddr_t paddr, int);
+static void rge_intr(void *);
+static void rge_start_locked(struct ifnet *, int);
+static void rge_start(struct ifnet *);
+static int rge_ioctl(struct ifnet *, u_long, caddr_t);
+static void rge_init(void *);
+static void rge_stop(struct rge_softc *);
+static void rge_watchdog(struct ifnet *);
+static int rge_shutdown(device_t);
+static void rge_reset(struct rge_softc *);
+
+static struct mbuf *get_mbuf(void);
+static void free_buf(vm_paddr_t paddr);
+static void *get_buf(void);
+
+static void xlr_mac_get_hwaddr(struct rge_softc *);
+static void xlr_mac_setup_hwaddr(struct driver_data *);
+static void rmi_xlr_mac_set_enable(struct driver_data *priv, int flag);
+static void rmi_xlr_xgmac_init(struct driver_data *priv);
+static void rmi_xlr_gmac_init(struct driver_data *priv);
+static void mac_common_init(void);
+static int rge_mii_write(device_t, int, int, int);
+static int rge_mii_read(device_t, int, int);
+static void rmi_xlr_mac_mii_statchg(device_t);
+static int rmi_xlr_mac_mediachange(struct ifnet *);
+static void rmi_xlr_mac_mediastatus(struct ifnet *, struct ifmediareq *);
+static void xlr_mac_set_rx_mode(struct rge_softc *sc);
+void
+rmi_xlr_mac_msgring_handler(int bucket, int size, int code,
+ int stid, struct msgrng_msg *msg,
+ void *data);
+static void mac_frin_replenish(void *);
+static int rmi_xlr_mac_open(struct rge_softc *);
+static int rmi_xlr_mac_close(struct rge_softc *);
+static int
+mac_xmit(struct mbuf *, struct rge_softc *,
+ struct driver_data *, int, struct p2d_tx_desc *);
+static int rmi_xlr_mac_xmit(struct mbuf *, struct rge_softc *, int, struct p2d_tx_desc *);
+static struct rge_softc_stats *rmi_xlr_mac_get_stats(struct rge_softc *sc);
+static void rmi_xlr_mac_set_multicast_list(struct rge_softc *sc);
+static int rmi_xlr_mac_change_mtu(struct rge_softc *sc, int new_mtu);
+static int rmi_xlr_mac_fill_rxfr(struct rge_softc *sc);
+static void rmi_xlr_config_spill_area(struct driver_data *priv);
+static int rmi_xlr_mac_set_speed(struct driver_data *s, xlr_mac_speed_t speed);
+static int
+rmi_xlr_mac_set_duplex(struct driver_data *s,
+ xlr_mac_duplex_t duplex, xlr_mac_fc_t fc);
+static void serdes_regs_init(struct driver_data *priv);
+static int rmi_xlr_gmac_reset(struct driver_data *priv);
+
+/*Statistics...*/
+static int get_p2d_desc_failed = 0;
+static int msg_snd_failed = 0;
+
+SYSCTL_INT(_hw, OID_AUTO, get_p2d_failed, CTLFLAG_RW,
+ &get_p2d_desc_failed, 0, "p2d desc failed");
+SYSCTL_INT(_hw, OID_AUTO, msg_snd_failed, CTLFLAG_RW,
+ &msg_snd_failed, 0, "msg snd failed");
+
+struct callout xlr_tx_stop_bkp;
+
+static device_method_t rge_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, rge_probe),
+ DEVMETHOD(device_attach, rge_attach),
+ DEVMETHOD(device_detach, rge_detach),
+ DEVMETHOD(device_shutdown, rge_shutdown),
+ DEVMETHOD(device_suspend, rge_suspend),
+ DEVMETHOD(device_resume, rge_resume),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, rge_mii_read),
+ DEVMETHOD(miibus_statchg, rmi_xlr_mac_mii_statchg),
+ DEVMETHOD(miibus_writereg, rge_mii_write),
+ {0, 0}
+};
+
+static driver_t rge_driver = {
+ "rge",
+ rge_methods,
+ sizeof(struct rge_softc)
+};
+
+static devclass_t rge_devclass;
+
+DRIVER_MODULE(rge, iodi, rge_driver, rge_devclass, 0, 0);
+DRIVER_MODULE(miibus, rge, miibus_driver, miibus_devclass, 0, 0);
+
+#ifndef __STR
+#define __STR(x) #x
+#endif
+#ifndef STR
+#define STR(x) __STR(x)
+#endif
+
+#define XKPHYS 0x8000000000000000
+/* -- No longer needed RRS
+static __inline__ uint32_t
+lw_40bit_phys(uint64_t phys, int cca)
+{
+ uint64_t addr;
+ uint32_t value = 0;
+ unsigned long flags;
+
+ addr = XKPHYS | ((uint64_t) cca << 59) | (phys & 0xfffffffffcULL);
+
+ enable_KX(flags);
+ __asm__ __volatile__(
+ ".set push\n"
+ ".set noreorder\n"
+ ".set mips64\n"
+ "lw %0, 0(%1) \n"
+ ".set pop\n"
+ : "=r"(value)
+ : "r"(addr));
+
+ disable_KX(flags);
+ return value;
+}
+*/
+/* -- No longer used RRS
+static __inline__ uint64_t
+ld_40bit_phys(uint64_t phys, int cca)
+{
+ uint64_t addr;
+ uint64_t value = 0;
+ unsigned long flags;
+
+
+ addr = XKPHYS | ((uint64_t) cca << 59) | (phys & 0xfffffffffcULL);
+ enable_KX(flags);
+ __asm__ __volatile__(
+ ".set push\n"
+ ".set noreorder\n"
+ ".set mips64\n"
+ "ld %0, 0(%1) \n"
+ ".set pop\n"
+ : "=r"(value)
+ : "r"(addr));
+
+ disable_KX(flags);
+ return value;
+}
+*/
+
+void *xlr_tx_ring_mem;
+
+struct tx_desc_node {
+ struct p2d_tx_desc *ptr;
+ TAILQ_ENTRY(tx_desc_node) list;
+};
+
+#define XLR_MAX_TX_DESC_NODES (XLR_MAX_MACS * MAX_P2D_DESC_PER_PORT)
+struct tx_desc_node tx_desc_nodes[XLR_MAX_TX_DESC_NODES];
+static volatile int xlr_tot_avail_p2d[XLR_MAX_CORE];
+static int xlr_total_active_core = 0;
+
+/*
+ * This should contain the list of all free tx frag desc nodes pointing to tx
+ * p2d arrays
+ */
+static
+TAILQ_HEAD(, tx_desc_node) tx_frag_desc[XLR_MAX_CORE] =
+{
+ TAILQ_HEAD_INITIALIZER(tx_frag_desc[0]),
+ TAILQ_HEAD_INITIALIZER(tx_frag_desc[1]),
+ TAILQ_HEAD_INITIALIZER(tx_frag_desc[2]),
+ TAILQ_HEAD_INITIALIZER(tx_frag_desc[3]),
+ TAILQ_HEAD_INITIALIZER(tx_frag_desc[4]),
+ TAILQ_HEAD_INITIALIZER(tx_frag_desc[5]),
+ TAILQ_HEAD_INITIALIZER(tx_frag_desc[6]),
+ TAILQ_HEAD_INITIALIZER(tx_frag_desc[7]),
+};
+
+/* This contains a list of free tx frag node descriptors */
+static
+TAILQ_HEAD(, tx_desc_node) free_tx_frag_desc[XLR_MAX_CORE] =
+{
+ TAILQ_HEAD_INITIALIZER(free_tx_frag_desc[0]),
+ TAILQ_HEAD_INITIALIZER(free_tx_frag_desc[1]),
+ TAILQ_HEAD_INITIALIZER(free_tx_frag_desc[2]),
+ TAILQ_HEAD_INITIALIZER(free_tx_frag_desc[3]),
+ TAILQ_HEAD_INITIALIZER(free_tx_frag_desc[4]),
+ TAILQ_HEAD_INITIALIZER(free_tx_frag_desc[5]),
+ TAILQ_HEAD_INITIALIZER(free_tx_frag_desc[6]),
+ TAILQ_HEAD_INITIALIZER(free_tx_frag_desc[7]),
+};
+
+static struct mtx tx_desc_lock[XLR_MAX_CORE];
+
+static inline void
+mac_make_desc_rfr(struct msgrng_msg *msg,
+ vm_paddr_t addr)
+{
+ msg->msg0 = (uint64_t) addr & 0xffffffffe0ULL;
+ msg->msg1 = msg->msg2 = msg->msg3 = 0;
+}
+
+#define MAC_TX_DESC_ALIGNMENT (XLR_CACHELINE_SIZE - 1)
+
+static void
+init_p2d_allocation(void)
+{
+ int active_core[8] = {0};
+ int i = 0;
+ uint32_t cpumask;
+ int cpu;
+
+ cpumask = PCPU_GET(cpumask) | PCPU_GET(other_cpus);
+
+ for (i = 0; i < 32; i++) {
+ if (cpumask & (1 << i)) {
+ cpu = cpu_ltop_map[i];
+ if (!active_core[cpu / 4]) {
+ active_core[cpu / 4] = 1;
+ xlr_total_active_core++;
+ }
+ }
+ }
+ for (i = 0; i < XLR_MAX_CORE; i++) {
+ if (active_core[i])
+ xlr_tot_avail_p2d[i] = XLR_MAX_TX_DESC_NODES / xlr_total_active_core;
+ }
+ printf("Total Active Core %d\n", xlr_total_active_core);
+}
+
+
+static void
+init_tx_ring(void)
+{
+ int i;
+ int j = 0;
+ struct tx_desc_node *start, *node;
+ struct p2d_tx_desc *tx_desc;
+ vm_paddr_t paddr;
+ vm_offset_t unmapped_addr;
+
+ for (i = 0; i < XLR_MAX_CORE; i++)
+ mtx_init(&tx_desc_lock[i], "xlr tx_desc", NULL, MTX_SPIN);
+
+ start = &tx_desc_nodes[0];
+ /* TODO: try to get this from KSEG0 */
+ xlr_tx_ring_mem = contigmalloc((MAX_TX_RING_SIZE + XLR_CACHELINE_SIZE),
+ M_DEVBUF, M_NOWAIT | M_ZERO, 0,
+ 0x10000000, XLR_CACHELINE_SIZE, 0);
+
+ if (xlr_tx_ring_mem == NULL) {
+ panic("TX ring memory allocation failed");
+ }
+ paddr = vtophys((vm_offset_t)xlr_tx_ring_mem);
+
+ unmapped_addr = MIPS_PHYS_TO_KSEG0(paddr);
+
+
+ tx_desc = (struct p2d_tx_desc *)unmapped_addr;
+
+ for (i = 0; i < XLR_MAX_TX_DESC_NODES; i++) {
+ node = start + i;
+ node->ptr = tx_desc;
+ tx_desc++;
+ TAILQ_INSERT_HEAD(&tx_frag_desc[j], node, list);
+ j = (i / (XLR_MAX_TX_DESC_NODES / xlr_total_active_core));
+ }
+}
+
+static inline struct p2d_tx_desc *
+get_p2d_desc(void)
+{
+ struct tx_desc_node *node;
+ struct p2d_tx_desc *tx_desc = NULL;
+ int cpu = xlr_cpu_id();
+
+ mtx_lock_spin(&tx_desc_lock[cpu]);
+ node = TAILQ_FIRST(&tx_frag_desc[cpu]);
+ if (node) {
+ xlr_tot_avail_p2d[cpu]--;
+ TAILQ_REMOVE(&tx_frag_desc[cpu], node, list);
+ tx_desc = node->ptr;
+ TAILQ_INSERT_HEAD(&free_tx_frag_desc[cpu], node, list);
+ } else {
+ /* Increment p2d desc fail count */
+ get_p2d_desc_failed++;
+ }
+ mtx_unlock_spin(&tx_desc_lock[cpu]);
+ return tx_desc;
+}
+static void
+free_p2d_desc(struct p2d_tx_desc *tx_desc)
+{
+ struct tx_desc_node *node;
+ int cpu = xlr_cpu_id();
+
+ mtx_lock_spin(&tx_desc_lock[cpu]);
+ node = TAILQ_FIRST(&free_tx_frag_desc[cpu]);
+ KASSERT((node != NULL), ("Free TX frag node list is empty\n"));
+
+ TAILQ_REMOVE(&free_tx_frag_desc[cpu], node, list);
+ node->ptr = tx_desc;
+ TAILQ_INSERT_HEAD(&tx_frag_desc[cpu], node, list);
+ xlr_tot_avail_p2d[cpu]++;
+ mtx_unlock_spin(&tx_desc_lock[cpu]);
+
+}
+
+static int
+build_frag_list(struct mbuf *m_head, struct msgrng_msg *p2p_msg, struct p2d_tx_desc *tx_desc)
+{
+ struct mbuf *m;
+ vm_paddr_t paddr;
+ uint64_t p2d_len;
+ int nfrag;
+ vm_paddr_t p1, p2;
+ uint32_t len1, len2;
+ vm_offset_t taddr;
+ uint64_t fr_stid;
+
+ fr_stid = (xlr_cpu_id() << 3) + xlr_thr_id() + 4;
+
+ if (tx_desc == NULL)
+ return 1;
+
+ nfrag = 0;
+ for (m = m_head; m != NULL; m = m->m_next) {
+ if ((nfrag + 1) >= XLR_MAX_TX_FRAGS) {
+ free_p2d_desc(tx_desc);
+ return 1;
+ }
+ if (m->m_len != 0) {
+ paddr = vtophys(mtod(m, vm_offset_t));
+ p1 = paddr + m->m_len;
+ p2 = vtophys(((vm_offset_t)m->m_data + m->m_len));
+ if (p1 != p2) {
+ len1 = (uint32_t)
+ (PAGE_SIZE - (paddr & PAGE_MASK));
+ tx_desc->frag[nfrag] = (127ULL << 54) |
+ ((uint64_t) len1 << 40) | paddr;
+ nfrag++;
+ taddr = (vm_offset_t)m->m_data + len1;
+ p2 = vtophys(taddr);
+ len2 = m->m_len - len1;
+ if (nfrag >= XLR_MAX_TX_FRAGS)
+ panic("TX frags exceeded");
+
+ tx_desc->frag[nfrag] = (127ULL << 54) |
+ ((uint64_t) len2 << 40) | p2;
+
+ taddr += len2;
+ p1 = vtophys(taddr);
+
+ if ((p2 + len2) != p1) {
+ printf("p1 = %p p2 = %p\n", (void *)p1, (void *)p2);
+ printf("len1 = %x len2 = %x\n", len1,
+ len2);
+ printf("m_data %p\n", m->m_data);
+ DELAY(1000000);
+ panic("Multiple Mbuf segment discontiguous\n");
+ }
+ } else {
+ tx_desc->frag[nfrag] = (127ULL << 54) |
+ ((uint64_t) m->m_len << 40) | paddr;
+ }
+ nfrag++;
+ }
+ }
+ /* set eop in the last tx p2d desc */
+ tx_desc->frag[nfrag - 1] |= (1ULL << 63);
+ paddr = vtophys((vm_offset_t)tx_desc);
+ tx_desc->frag[nfrag] = (1ULL << 63) | (fr_stid << 54) | paddr;
+ nfrag++;
+ tx_desc->frag[XLR_MAX_TX_FRAGS] = (uint64_t) (vm_offset_t)tx_desc;
+ tx_desc->frag[XLR_MAX_TX_FRAGS + 1] = (uint64_t) (vm_offset_t)m_head;
+
+ p2d_len = (nfrag * 8);
+ p2p_msg->msg0 = (1ULL << 63) | (1ULL << 62) | (127ULL << 54) |
+ (p2d_len << 40) | paddr;
+
+ return 0;
+}
+static void
+release_tx_desc(struct msgrng_msg *msg, int rel_buf)
+{
+ /*
+ * OLD code: vm_paddr_t paddr = msg->msg0 & 0xffffffffffULL;
+ * uint64_t temp; struct p2d_tx_desc *tx_desc; struct mbuf *m;
+ *
+ * paddr += (XLR_MAX_TX_FRAGS * sizeof(uint64_t)); *** In o32 we will
+ * crash here ****** temp = ld_40bit_phys(paddr, 3); tx_desc =
+ * (struct p2d_tx_desc *)((vm_offset_t)temp);
+ *
+ * if (rel_buf) { paddr += sizeof(uint64_t);
+ *
+ * temp = ld_40bit_phys(paddr, 3);
+ *
+ * m = (struct mbuf *)((vm_offset_t)temp); m_freem(m); } printf("Call
+ * fre_p2d_desc\n"); free_p2d_desc(tx_desc);
+ */
+ struct p2d_tx_desc *tx_desc, *chk_addr;
+ struct mbuf *m;
+
+ tx_desc = (struct p2d_tx_desc *)MIPS_PHYS_TO_KSEG0(msg->msg0);
+ chk_addr = (struct p2d_tx_desc *)(uint32_t) (tx_desc->frag[XLR_MAX_TX_FRAGS] & 0x00000000ffffffff);
+ if (tx_desc != chk_addr) {
+ printf("Address %p does not match with stored addr %p - we leaked a descriptor\n",
+ tx_desc, chk_addr);
+ return;
+ }
+ if (rel_buf) {
+ m = (struct mbuf *)(uint32_t) (tx_desc->frag[XLR_MAX_TX_FRAGS + 1] & 0x00000000ffffffff);
+ m_freem(m);
+ }
+ free_p2d_desc(tx_desc);
+}
+
+#ifdef RX_COPY
+#define RGE_MAX_NUM_DESC (6 * MAX_NUM_DESC)
+uint8_t *rge_rx_buffers[RGE_MAX_NUM_DESC];
+static struct mtx rge_rx_mtx;
+int g_rx_buf_head;
+
+static void
+init_rx_buf(void)
+{
+ int i;
+ uint8_t *buf, *start;
+ uint32_t size, *ptr;
+
+ mtx_init(&rge_rx_mtx, "xlr rx_desc", NULL, MTX_SPIN);
+
+ size = (RGE_MAX_NUM_DESC * (MAX_FRAME_SIZE + XLR_CACHELINE_SIZE));
+
+ start = (uint8_t *) contigmalloc(size, M_DEVBUF, M_NOWAIT | M_ZERO,
+ 0, 0xffffffff, XLR_CACHELINE_SIZE, 0);
+ if (start == NULL)
+ panic("NO RX BUFFERS");
+ buf = start;
+ size = (MAX_FRAME_SIZE + XLR_CACHELINE_SIZE);
+ for (i = 0; i < RGE_MAX_NUM_DESC; i++) {
+ buf = start + (i * size);
+ ptr = (uint32_t *) buf;
+ *ptr = (uint32_t) buf;
+ rge_rx_buffers[i] = buf + XLR_CACHELINE_SIZE;
+ }
+}
+
+static void *
+get_rx_buf(void)
+{
+ void *ptr = NULL;
+
+ mtx_lock_spin(&rge_rx_mtx);
+ if (g_rx_buf_head < RGE_MAX_NUM_DESC) {
+ ptr = (void *)rge_rx_buffers[g_rx_buf_head];
+ g_rx_buf_head++;
+ }
+ mtx_unlock_spin(&rge_rx_mtx);
+ return ptr;
+}
+
+#endif
+
+static struct mbuf *
+get_mbuf(void)
+{
+ struct mbuf *m_new = NULL;
+
+ if ((m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR)) == NULL)
+ return NULL;
+
+ m_new->m_len = MCLBYTES;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ return m_new;
+}
+
+static void
+free_buf(vm_paddr_t paddr)
+{
+ struct mbuf *m;
+ uint32_t *temp;
+ uint32_t mag, um;
+
+ /*
+ * This will crash I think. RRS temp = lw_40bit_phys((paddr -
+ * XLR_CACHELINE_SIZE), 3); m = (struct mbuf *)temp;
+ */
+ /*
+ * This gets us a kseg0 address for the mbuf/magic on the ring but
+ * we need to get the va to free the mbuf. This is stored at *temp;
+ */
+ temp = (uint32_t *) MIPS_PHYS_TO_KSEG0(paddr - XLR_CACHELINE_SIZE);
+ um = temp[0];
+ mag = temp[1];
+ if (mag != 0xf00bad) {
+ printf("Something is wrong kseg:%p found mag:%x not 0xf00bad\n",
+ temp, mag);
+ return;
+ }
+ m = (struct mbuf *)um;
+ if (m != NULL)
+ m_freem(m);
+}
+
+static void *
+get_buf(void)
+{
+#ifdef RX_COPY
+ return get_rx_buf();
+#else
+ struct mbuf *m_new = NULL;
+
+#ifdef INVARIANTS
+ vm_paddr_t temp1, temp2;
+
+#endif
+ unsigned int *md;
+
+ m_new = get_mbuf();
+
+ if (m_new == NULL)
+ return NULL;
+
+ m_adj(m_new, XLR_CACHELINE_SIZE - ((unsigned int)m_new->m_data & 0x1f));
+ md = (unsigned int *)m_new->m_data;
+ md[0] = (unsigned int)m_new; /* Back Ptr */
+ md[1] = 0xf00bad;
+ m_adj(m_new, XLR_CACHELINE_SIZE);
+
+
+ /* return (void *)m_new; */
+#ifdef INVARIANTS
+ temp1 = vtophys((vm_offset_t)m_new->m_data);
+ temp2 = vtophys((vm_offset_t)m_new->m_data + 1536);
+ if ((temp1 + 1536) != temp2)
+ panic("ALLOCED BUFFER IS NOT CONTIGUOUS\n");
+#endif
+ return (void *)m_new->m_data;
+#endif
+}
+
+/**********************************************************************
+ **********************************************************************/
+static void
+rmi_xlr_mac_set_enable(struct driver_data *priv, int flag)
+{
+ uint32_t regval;
+ int tx_threshold = 1518;
+
+ if (flag) {
+ regval = xlr_read_reg(priv->mmio, R_TX_CONTROL);
+ regval |= (1 << O_TX_CONTROL__TxEnable) |
+ (tx_threshold << O_TX_CONTROL__TxThreshold);
+
+ xlr_write_reg(priv->mmio, R_TX_CONTROL, regval);
+
+ regval = xlr_read_reg(priv->mmio, R_RX_CONTROL);
+ regval |= 1 << O_RX_CONTROL__RxEnable;
+ if (priv->mode == XLR_PORT0_RGMII)
+ regval |= 1 << O_RX_CONTROL__RGMII;
+ xlr_write_reg(priv->mmio, R_RX_CONTROL, regval);
+
+ regval = xlr_read_reg(priv->mmio, R_MAC_CONFIG_1);
+ regval |= (O_MAC_CONFIG_1__txen | O_MAC_CONFIG_1__rxen);
+ xlr_write_reg(priv->mmio, R_MAC_CONFIG_1, regval);
+ } else {
+ regval = xlr_read_reg(priv->mmio, R_TX_CONTROL);
+ regval &= ~((1 << O_TX_CONTROL__TxEnable) |
+ (tx_threshold << O_TX_CONTROL__TxThreshold));
+
+ xlr_write_reg(priv->mmio, R_TX_CONTROL, regval);
+
+ regval = xlr_read_reg(priv->mmio, R_RX_CONTROL);
+ regval &= ~(1 << O_RX_CONTROL__RxEnable);
+ xlr_write_reg(priv->mmio, R_RX_CONTROL, regval);
+
+ regval = xlr_read_reg(priv->mmio, R_MAC_CONFIG_1);
+ regval &= ~(O_MAC_CONFIG_1__txen | O_MAC_CONFIG_1__rxen);
+ xlr_write_reg(priv->mmio, R_MAC_CONFIG_1, regval);
+ }
+}
+
+/**********************************************************************
+ **********************************************************************/
+static __inline__ int
+xlr_mac_send_fr(struct driver_data *priv,
+ vm_paddr_t addr, int len)
+{
+ int stid = priv->rfrbucket;
+ struct msgrng_msg msg;
+ int vcpu = (xlr_cpu_id() << 2) + xlr_thr_id();
+
+ mac_make_desc_rfr(&msg, addr);
+
+ /* Send the packet to MAC */
+ dbg_msg("mac_%d: Sending free packet %llx to stid %d\n",
+ priv->instance, addr, stid);
+ if (priv->type == XLR_XGMAC) {
+ while (message_send(1, MSGRNG_CODE_XGMAC, stid, &msg));
+ } else {
+ while (message_send(1, MSGRNG_CODE_MAC, stid, &msg));
+ xlr_rge_repl_done[vcpu]++;
+ }
+
+ return 0;
+}
+
+/**************************************************************/
+
+static void
+xgmac_mdio_setup(volatile unsigned int *_mmio)
+{
+ int i;
+ uint32_t rd_data;
+
+ for (i = 0; i < 4; i++) {
+ rd_data = xmdio_read(_mmio, 1, 0x8000 + i);
+ rd_data = rd_data & 0xffffdfff; /* clear isolate bit */
+ xmdio_write(_mmio, 1, 0x8000 + i, rd_data);
+ }
+}
+
+/**********************************************************************
+ * Init MII interface
+ *
+ * Input parameters:
+ * s - priv structure
+ ********************************************************************* */
+#define PHY_STATUS_RETRIES 25000
+
+static void
+rmi_xlr_mac_mii_init(struct driver_data *priv)
+{
+ xlr_reg_t *mii_mmio = priv->mii_mmio;
+
+ /* use the lowest clock divisor - divisor 28 */
+ xlr_write_reg(mii_mmio, R_MII_MGMT_CONFIG, 0x07);
+}
+
+/**********************************************************************
+ * Read a PHY register.
+ *
+ * Input parameters:
+ * s - priv structure
+ * phyaddr - PHY's address
+ * regidx = index of register to read
+ *
+ * Return value:
+ * value read, or 0 if an error occurred.
+ ********************************************************************* */
+
+static int
+rge_mii_read_internal(xlr_reg_t * mii_mmio, int phyaddr, int regidx)
+{
+ int i = 0;
+
+ /* setup the phy reg to be used */
+ xlr_write_reg(mii_mmio, R_MII_MGMT_ADDRESS,
+ (phyaddr << 8) | (regidx << 0));
+ /* Issue the read command */
+ xlr_write_reg(mii_mmio, R_MII_MGMT_COMMAND,
+ (1 << O_MII_MGMT_COMMAND__rstat));
+
+ /* poll for the read cycle to complete */
+ for (i = 0; i < PHY_STATUS_RETRIES; i++) {
+ if (xlr_read_reg(mii_mmio, R_MII_MGMT_INDICATORS) == 0)
+ break;
+ }
+
+ /* clear the read cycle */
+ xlr_write_reg(mii_mmio, R_MII_MGMT_COMMAND, 0);
+
+ if (i == PHY_STATUS_RETRIES) {
+ return 0xffffffff;
+ }
+ /* Read the data back */
+ return xlr_read_reg(mii_mmio, R_MII_MGMT_STATUS);
+}
+
+static int
+rge_mii_read(device_t dev, int phyaddr, int regidx)
+{
+ struct rge_softc *sc = device_get_softc(dev);
+
+ return rge_mii_read_internal(sc->priv.mii_mmio, phyaddr, regidx);
+}
+
+/**********************************************************************
+ * Set MII hooks to newly selected media
+ *
+ * Input parameters:
+ * ifp - Interface Pointer
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static int
+rmi_xlr_mac_mediachange(struct ifnet *ifp)
+{
+ struct rge_softc *sc = ifp->if_softc;
+
+ if (ifp->if_flags & IFF_UP)
+ mii_mediachg(&sc->rge_mii);
+
+ return 0;
+}
+
+/**********************************************************************
+ * Get the current interface media status
+ *
+ * Input parameters:
+ * ifp - Interface Pointer
+ * ifmr - Interface media request ptr
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+rmi_xlr_mac_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct rge_softc *sc = ifp->if_softc;
+
+ /* Check whether this is interface is active or not. */
+ ifmr->ifm_status = IFM_AVALID;
+ if (sc->link_up) {
+ ifmr->ifm_status |= IFM_ACTIVE;
+ } else {
+ ifmr->ifm_active = IFM_ETHER;
+ }
+}
+
+/**********************************************************************
+ * Write a value to a PHY register.
+ *
+ * Input parameters:
+ * s - priv structure
+ * phyaddr - PHY to use
+ * regidx - register within the PHY
+ * regval - data to write to register
+ *
+ * Return value:
+ * nothing
+ ********************************************************************* */
+static void
+rge_mii_write_internal(xlr_reg_t * mii_mmio, int phyaddr, int regidx, int regval)
+{
+ int i = 0;
+
+ xlr_write_reg(mii_mmio, R_MII_MGMT_ADDRESS,
+ (phyaddr << 8) | (regidx << 0));
+
+ /* Write the data which starts the write cycle */
+ xlr_write_reg(mii_mmio, R_MII_MGMT_WRITE_DATA, regval);
+
+ /* poll for the write cycle to complete */
+ for (i = 0; i < PHY_STATUS_RETRIES; i++) {
+ if (xlr_read_reg(mii_mmio, R_MII_MGMT_INDICATORS) == 0)
+ break;
+ }
+
+ return;
+}
+
+static int
+rge_mii_write(device_t dev, int phyaddr, int regidx, int regval)
+{
+ struct rge_softc *sc = device_get_softc(dev);
+
+ rge_mii_write_internal(sc->priv.mii_mmio, phyaddr, regidx, regval);
+ return (0);
+}
+
+static void
+rmi_xlr_mac_mii_statchg(struct device *dev)
+{
+}
+
+static void
+serdes_regs_init(struct driver_data *priv)
+{
+ xlr_reg_t *mmio_gpio = (xlr_reg_t *) (xlr_io_base + XLR_IO_GPIO_OFFSET);
+ int i;
+
+ /* Initialize SERDES CONTROL Registers */
+ rge_mii_write_internal(priv->serdes_mmio, 26, 0, 0x6DB0);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 1, 0xFFFF);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 2, 0xB6D0);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 3, 0x00FF);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 4, 0x0000);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 5, 0x0000);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 6, 0x0005);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 7, 0x0001);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 8, 0x0000);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 9, 0x0000);
+ rge_mii_write_internal(priv->serdes_mmio, 26, 10, 0x0000);
+
+ /*
+ * For loop delay and GPIO programming crud from Linux driver,
+ */
+ for (i = 0; i < 10000000; i++) {
+ }
+ mmio_gpio[0x20] = 0x7e6802;
+ mmio_gpio[0x10] = 0x7104;
+ for (i = 0; i < 100000000; i++) {
+ }
+ return;
+}
+
+static void
+serdes_autoconfig(struct driver_data *priv)
+{
+ int delay = 100000;
+
+ /* Enable Auto negotiation in the PCS Layer */
+ rge_mii_write_internal(priv->pcs_mmio, 27, 0, 0x1000);
+ DELAY(delay);
+ rge_mii_write_internal(priv->pcs_mmio, 27, 0, 0x0200);
+ DELAY(delay);
+
+ rge_mii_write_internal(priv->pcs_mmio, 28, 0, 0x1000);
+ DELAY(delay);
+ rge_mii_write_internal(priv->pcs_mmio, 28, 0, 0x0200);
+ DELAY(delay);
+
+ rge_mii_write_internal(priv->pcs_mmio, 29, 0, 0x1000);
+ DELAY(delay);
+ rge_mii_write_internal(priv->pcs_mmio, 29, 0, 0x0200);
+ DELAY(delay);
+
+ rge_mii_write_internal(priv->pcs_mmio, 30, 0, 0x1000);
+ DELAY(delay);
+ rge_mii_write_internal(priv->pcs_mmio, 30, 0, 0x0200);
+ DELAY(delay);
+
+}
+
+/*****************************************************************
+ * Initialize GMAC
+ *****************************************************************/
+static void
+rmi_xlr_config_pde(struct driver_data *priv)
+{
+ int i = 0, cpu = 0, bucket = 0;
+ uint64_t bucket_map = 0;
+
+ /* uint32_t desc_pack_ctrl = 0; */
+ uint32_t cpumask;
+
+ cpumask = PCPU_GET(cpumask) | PCPU_GET(other_cpus);
+
+ for (i = 0; i < 32; i++) {
+ if (cpumask & (1 << i)) {
+ cpu = cpu_ltop_map[i];
+ bucket = ((cpu >> 2) << 3);
+ //|(cpu & 0x03);
+ bucket_map |= (1ULL << bucket);
+ dbg_msg("i=%d, cpu=%d, bucket = %d, bucket_map=%llx\n",
+ i, cpu, bucket, bucket_map);
+ }
+ }
+
+ /* bucket_map = 0x1; */
+ xlr_write_reg(priv->mmio, R_PDE_CLASS_0, (bucket_map & 0xffffffff));
+ xlr_write_reg(priv->mmio, R_PDE_CLASS_0 + 1,
+ ((bucket_map >> 32) & 0xffffffff));
+
+ xlr_write_reg(priv->mmio, R_PDE_CLASS_1, (bucket_map & 0xffffffff));
+ xlr_write_reg(priv->mmio, R_PDE_CLASS_1 + 1,
+ ((bucket_map >> 32) & 0xffffffff));
+
+ xlr_write_reg(priv->mmio, R_PDE_CLASS_2, (bucket_map & 0xffffffff));
+ xlr_write_reg(priv->mmio, R_PDE_CLASS_2 + 1,
+ ((bucket_map >> 32) & 0xffffffff));
+
+ xlr_write_reg(priv->mmio, R_PDE_CLASS_3, (bucket_map & 0xffffffff));
+ xlr_write_reg(priv->mmio, R_PDE_CLASS_3 + 1,
+ ((bucket_map >> 32) & 0xffffffff));
+}
+
+static void
+rmi_xlr_config_parser(struct driver_data *priv)
+{
+ /*
+ * Mark it as no classification The parser extract is gauranteed to
+ * be zero with no classfication
+ */
+ xlr_write_reg(priv->mmio, R_L2TYPE_0, 0x00);
+
+ xlr_write_reg(priv->mmio, R_L2TYPE_0, 0x01);
+
+ /* configure the parser : L2 Type is configured in the bootloader */
+ /* extract IP: src, dest protocol */
+ xlr_write_reg(priv->mmio, R_L3CTABLE,
+ (9 << 20) | (1 << 19) | (1 << 18) | (0x01 << 16) |
+ (0x0800 << 0));
+ xlr_write_reg(priv->mmio, R_L3CTABLE + 1,
+ (12 << 25) | (4 << 21) | (16 << 14) | (4 << 10));
+
+}
+
+static void
+rmi_xlr_config_classifier(struct driver_data *priv)
+{
+ int i = 0;
+
+ if (priv->type == XLR_XGMAC) {
+ /* xgmac translation table doesn't have sane values on reset */
+ for (i = 0; i < 64; i++)
+ xlr_write_reg(priv->mmio, R_TRANSLATETABLE + i, 0x0);
+
+ /*
+ * use upper 7 bits of the parser extract to index the
+ * translate table
+ */
+ xlr_write_reg(priv->mmio, R_PARSERCONFIGREG, 0x0);
+ }
+}
+
+enum {
+ SGMII_SPEED_10 = 0x00000000,
+ SGMII_SPEED_100 = 0x02000000,
+ SGMII_SPEED_1000 = 0x04000000,
+};
+
+static void
+rmi_xlr_gmac_config_speed(struct driver_data *priv)
+{
+ int phy_addr = priv->phy_addr;
+ xlr_reg_t *mmio = priv->mmio;
+ struct rge_softc *sc = priv->sc;
+
+ priv->speed = rge_mii_read_internal(priv->mii_mmio, phy_addr, 28);
+ priv->link = rge_mii_read_internal(priv->mii_mmio, phy_addr, 1) & 0x4;
+ priv->speed = (priv->speed >> 3) & 0x03;
+
+ if (priv->speed == xlr_mac_speed_10) {
+ if (priv->mode != XLR_RGMII)
+ xlr_write_reg(mmio, R_INTERFACE_CONTROL, SGMII_SPEED_10);
+ xlr_write_reg(mmio, R_MAC_CONFIG_2, 0x7137);
+ xlr_write_reg(mmio, R_CORECONTROL, 0x02);
+ printf("%s: [10Mbps]\n", device_get_nameunit(sc->rge_dev));
+ sc->rge_mii.mii_media.ifm_media = IFM_ETHER | IFM_AUTO | IFM_10_T | IFM_FDX;
+ sc->rge_mii.mii_media.ifm_cur->ifm_media = IFM_ETHER | IFM_AUTO | IFM_10_T | IFM_FDX;
+ sc->rge_mii.mii_media_active = IFM_ETHER | IFM_AUTO | IFM_10_T | IFM_FDX;
+ } else if (priv->speed == xlr_mac_speed_100) {
+ if (priv->mode != XLR_RGMII)
+ xlr_write_reg(mmio, R_INTERFACE_CONTROL, SGMII_SPEED_100);
+ xlr_write_reg(mmio, R_MAC_CONFIG_2, 0x7137);
+ xlr_write_reg(mmio, R_CORECONTROL, 0x01);
+ printf("%s: [100Mbps]\n", device_get_nameunit(sc->rge_dev));
+ sc->rge_mii.mii_media.ifm_media = IFM_ETHER | IFM_AUTO | IFM_100_TX | IFM_FDX;
+ sc->rge_mii.mii_media.ifm_cur->ifm_media = IFM_ETHER | IFM_AUTO | IFM_100_TX | IFM_FDX;
+ sc->rge_mii.mii_media_active = IFM_ETHER | IFM_AUTO | IFM_100_TX | IFM_FDX;
+ } else {
+ if (priv->speed != xlr_mac_speed_1000) {
+ if (priv->mode != XLR_RGMII)
+ xlr_write_reg(mmio, R_INTERFACE_CONTROL, SGMII_SPEED_100);
+ printf("PHY reported unknown MAC speed, defaulting to 100Mbps\n");
+ xlr_write_reg(mmio, R_MAC_CONFIG_2, 0x7137);
+ xlr_write_reg(mmio, R_CORECONTROL, 0x01);
+ sc->rge_mii.mii_media.ifm_media = IFM_ETHER | IFM_AUTO | IFM_100_TX | IFM_FDX;
+ sc->rge_mii.mii_media.ifm_cur->ifm_media = IFM_ETHER | IFM_AUTO | IFM_100_TX | IFM_FDX;
+ sc->rge_mii.mii_media_active = IFM_ETHER | IFM_AUTO | IFM_100_TX | IFM_FDX;
+ } else {
+ if (priv->mode != XLR_RGMII)
+ xlr_write_reg(mmio, R_INTERFACE_CONTROL, SGMII_SPEED_1000);
+ xlr_write_reg(mmio, R_MAC_CONFIG_2, 0x7237);
+ xlr_write_reg(mmio, R_CORECONTROL, 0x00);
+ printf("%s: [1000Mbps]\n", device_get_nameunit(sc->rge_dev));
+ sc->rge_mii.mii_media.ifm_media = IFM_ETHER | IFM_AUTO | IFM_1000_T | IFM_FDX;
+ sc->rge_mii.mii_media.ifm_cur->ifm_media = IFM_ETHER | IFM_AUTO | IFM_1000_T | IFM_FDX;
+ sc->rge_mii.mii_media_active = IFM_ETHER | IFM_AUTO | IFM_1000_T | IFM_FDX;
+ }
+ }
+
+ if (!priv->link) {
+ sc->rge_mii.mii_media.ifm_cur->ifm_media = IFM_ETHER;
+ sc->link_up = 0;
+ } else {
+ sc->link_up = 1;
+ }
+}
+
+/*****************************************************************
+ * Initialize XGMAC
+ *****************************************************************/
+static void
+rmi_xlr_xgmac_init(struct driver_data *priv)
+{
+ int i = 0;
+ xlr_reg_t *mmio = priv->mmio;
+ int id = priv->instance;
+ struct rge_softc *sc = priv->sc;
+ volatile unsigned short *cpld;
+
+ cpld = (volatile unsigned short *)0xBD840000;
+
+ xlr_write_reg(priv->mmio, R_DESC_PACK_CTRL,
+ (MAX_FRAME_SIZE << O_DESC_PACK_CTRL__RegularSize) | (4 << 20));
+ xlr_write_reg(priv->mmio, R_BYTEOFFSET0, BYTE_OFFSET);
+ rmi_xlr_config_pde(priv);
+ rmi_xlr_config_parser(priv);
+ rmi_xlr_config_classifier(priv);
+
+ xlr_write_reg(priv->mmio, R_MSG_TX_THRESHOLD, 1);
+
+ /* configure the XGMAC Registers */
+ xlr_write_reg(mmio, R_XGMAC_CONFIG_1, 0x50000026);
+
+ /* configure the XGMAC_GLUE Registers */
+ xlr_write_reg(mmio, R_DMACR0, 0xffffffff);
+ xlr_write_reg(mmio, R_DMACR1, 0xffffffff);
+ xlr_write_reg(mmio, R_DMACR2, 0xffffffff);
+ xlr_write_reg(mmio, R_DMACR3, 0xffffffff);
+ xlr_write_reg(mmio, R_STATCTRL, 0x04);
+ xlr_write_reg(mmio, R_L2ALLOCCTRL, 0xffffffff);
+
+ xlr_write_reg(mmio, R_XGMACPADCALIBRATION, 0x030);
+ xlr_write_reg(mmio, R_EGRESSFIFOCARVINGSLOTS, 0x0f);
+ xlr_write_reg(mmio, R_L2ALLOCCTRL, 0xffffffff);
+ xlr_write_reg(mmio, R_XGMAC_MIIM_CONFIG, 0x3e);
+
+ /*
+ * take XGMII phy out of reset
+ */
+ /*
+ * we are pulling everything out of reset because writing a 0 would
+ * reset other devices on the chip
+ */
+ cpld[ATX_CPLD_RESET_1] = 0xffff;
+ cpld[ATX_CPLD_MISC_CTRL] = 0xffff;
+ cpld[ATX_CPLD_RESET_2] = 0xffff;
+
+ xgmac_mdio_setup(mmio);
+
+ rmi_xlr_config_spill_area(priv);
+
+ if (id == 0) {
+ for (i = 0; i < 16; i++) {
+ xlr_write_reg(mmio, R_XGS_TX0_BUCKET_SIZE + i,
+ bucket_sizes.
+ bucket[MSGRNG_STNID_XGS0_TX + i]);
+ }
+
+ xlr_write_reg(mmio, R_XGS_JFR_BUCKET_SIZE,
+ bucket_sizes.bucket[MSGRNG_STNID_XMAC0JFR]);
+ xlr_write_reg(mmio, R_XGS_RFR_BUCKET_SIZE,
+ bucket_sizes.bucket[MSGRNG_STNID_XMAC0RFR]);
+
+ for (i = 0; i < MAX_NUM_MSGRNG_STN_CC; i++) {
+ xlr_write_reg(mmio, R_CC_CPU0_0 + i,
+ cc_table_xgs_0.
+ counters[i >> 3][i & 0x07]);
+ }
+ } else if (id == 1) {
+ for (i = 0; i < 16; i++) {
+ xlr_write_reg(mmio, R_XGS_TX0_BUCKET_SIZE + i,
+ bucket_sizes.
+ bucket[MSGRNG_STNID_XGS1_TX + i]);
+ }
+
+ xlr_write_reg(mmio, R_XGS_JFR_BUCKET_SIZE,
+ bucket_sizes.bucket[MSGRNG_STNID_XMAC1JFR]);
+ xlr_write_reg(mmio, R_XGS_RFR_BUCKET_SIZE,
+ bucket_sizes.bucket[MSGRNG_STNID_XMAC1RFR]);
+
+ for (i = 0; i < MAX_NUM_MSGRNG_STN_CC; i++) {
+ xlr_write_reg(mmio, R_CC_CPU0_0 + i,
+ cc_table_xgs_1.
+ counters[i >> 3][i & 0x07]);
+ }
+ }
+ sc->rge_mii.mii_media.ifm_media = IFM_ETHER | IFM_AUTO | IFM_10G_SR | IFM_FDX;
+ sc->rge_mii.mii_media.ifm_media |= (IFM_AVALID | IFM_ACTIVE);
+ sc->rge_mii.mii_media.ifm_cur->ifm_media = IFM_ETHER | IFM_AUTO | IFM_10G_SR | IFM_FDX;
+ sc->rge_mii.mii_media_active = IFM_ETHER | IFM_AUTO | IFM_10G_SR | IFM_FDX;
+ sc->rge_mii.mii_media.ifm_cur->ifm_media |= (IFM_AVALID | IFM_ACTIVE);
+
+ priv->init_frin_desc = 1;
+}
+
+/*******************************************************
+ * Initialization gmac
+ *******************************************************/
+static int
+rmi_xlr_gmac_reset(struct driver_data *priv)
+{
+ volatile uint32_t val;
+ xlr_reg_t *mmio = priv->mmio;
+ int i, maxloops = 100;
+
+ /* Disable MAC RX */
+ val = xlr_read_reg(mmio, R_MAC_CONFIG_1);
+ val &= ~0x4;
+ xlr_write_reg(mmio, R_MAC_CONFIG_1, val);
+
+ /* Disable Core RX */
+ val = xlr_read_reg(mmio, R_RX_CONTROL);
+ val &= ~0x1;
+ xlr_write_reg(mmio, R_RX_CONTROL, val);
+
+ /* wait for rx to halt */
+ for (i = 0; i < maxloops; i++) {
+ val = xlr_read_reg(mmio, R_RX_CONTROL);
+ if (val & 0x2)
+ break;
+ DELAY(1000);
+ }
+ if (i == maxloops)
+ return -1;
+
+ /* Issue a soft reset */
+ val = xlr_read_reg(mmio, R_RX_CONTROL);
+ val |= 0x4;
+ xlr_write_reg(mmio, R_RX_CONTROL, val);
+
+ /* wait for reset to complete */
+ for (i = 0; i < maxloops; i++) {
+ val = xlr_read_reg(mmio, R_RX_CONTROL);
+ if (val & 0x8)
+ break;
+ DELAY(1000);
+ }
+ if (i == maxloops)
+ return -1;
+
+ /* Clear the soft reset bit */
+ val = xlr_read_reg(mmio, R_RX_CONTROL);
+ val &= ~0x4;
+ xlr_write_reg(mmio, R_RX_CONTROL, val);
+ return 0;
+}
+
+static void
+rmi_xlr_gmac_init(struct driver_data *priv)
+{
+ int i = 0;
+ xlr_reg_t *mmio = priv->mmio;
+ int id = priv->instance;
+ struct stn_cc *gmac_cc_config;
+ uint32_t value = 0;
+ int blk = id / 4, port = id % 4;
+
+ rmi_xlr_mac_set_enable(priv, 0);
+
+ rmi_xlr_config_spill_area(priv);
+
+ xlr_write_reg(mmio, R_DESC_PACK_CTRL,
+ (BYTE_OFFSET << O_DESC_PACK_CTRL__ByteOffset) |
+ (1 << O_DESC_PACK_CTRL__MaxEntry) |
+ (MAX_FRAME_SIZE << O_DESC_PACK_CTRL__RegularSize));
+
+ rmi_xlr_config_pde(priv);
+ rmi_xlr_config_parser(priv);
+ rmi_xlr_config_classifier(priv);
+
+ xlr_write_reg(mmio, R_MSG_TX_THRESHOLD, 3);
+ xlr_write_reg(mmio, R_MAC_CONFIG_1, 0x35);
+ xlr_write_reg(mmio, R_RX_CONTROL, (0x7 << 6));
+
+ if (priv->mode == XLR_PORT0_RGMII) {
+ printf("Port 0 set in RGMII mode\n");
+ value = xlr_read_reg(mmio, R_RX_CONTROL);
+ value |= 1 << O_RX_CONTROL__RGMII;
+ xlr_write_reg(mmio, R_RX_CONTROL, value);
+ }
+ rmi_xlr_mac_mii_init(priv);
+
+
+#if 0
+ priv->advertising = ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half |
+ ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half |
+ ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
+ ADVERTISED_MII;
+#endif
+
+ /*
+ * Enable all MDIO interrupts in the phy RX_ER bit seems to be get
+ * set about every 1 sec in GigE mode, ignore it for now...
+ */
+ rge_mii_write_internal(priv->mii_mmio, priv->phy_addr, 25, 0xfffffffe);
+
+ if (priv->mode != XLR_RGMII) {
+ serdes_regs_init(priv);
+ serdes_autoconfig(priv);
+ }
+ rmi_xlr_gmac_config_speed(priv);
+
+ value = xlr_read_reg(mmio, R_IPG_IFG);
+ xlr_write_reg(mmio, R_IPG_IFG, ((value & ~0x7f) | MAC_B2B_IPG));
+ xlr_write_reg(mmio, R_DMACR0, 0xffffffff);
+ xlr_write_reg(mmio, R_DMACR1, 0xffffffff);
+ xlr_write_reg(mmio, R_DMACR2, 0xffffffff);
+ xlr_write_reg(mmio, R_DMACR3, 0xffffffff);
+ xlr_write_reg(mmio, R_STATCTRL, 0x04);
+ xlr_write_reg(mmio, R_L2ALLOCCTRL, 0xffffffff);
+ xlr_write_reg(mmio, R_INTMASK, 0);
+ xlr_write_reg(mmio, R_FREEQCARVE, 0);
+
+ xlr_write_reg(mmio, R_GMAC_TX0_BUCKET_SIZE + port,
+ xlr_board_info.bucket_sizes->bucket[priv->txbucket]);
+ xlr_write_reg(mmio, R_GMAC_JFR0_BUCKET_SIZE,
+ xlr_board_info.bucket_sizes->bucket[MSGRNG_STNID_GMACJFR_0]);
+ xlr_write_reg(mmio, R_GMAC_RFR0_BUCKET_SIZE,
+ xlr_board_info.bucket_sizes->bucket[MSGRNG_STNID_GMACRFR_0]);
+ xlr_write_reg(mmio, R_GMAC_JFR1_BUCKET_SIZE,
+ xlr_board_info.bucket_sizes->bucket[MSGRNG_STNID_GMACJFR_1]);
+ xlr_write_reg(mmio, R_GMAC_RFR1_BUCKET_SIZE,
+ xlr_board_info.bucket_sizes->bucket[MSGRNG_STNID_GMACRFR_1]);
+
+ dbg_msg("Programming credit counter %d : %d -> %d\n", blk, R_GMAC_TX0_BUCKET_SIZE + port,
+ xlr_board_info.bucket_sizes->bucket[priv->txbucket]);
+
+ gmac_cc_config = xlr_board_info.gmac_block[blk].credit_config;
+ for (i = 0; i < MAX_NUM_MSGRNG_STN_CC; i++) {
+ xlr_write_reg(mmio, R_CC_CPU0_0 + i,
+ gmac_cc_config->counters[i >> 3][i & 0x07]);
+ dbg_msg("%d: %d -> %d\n", priv->instance,
+ R_CC_CPU0_0 + i, gmac_cc_config->counters[i >> 3][i & 0x07]);
+ }
+ priv->init_frin_desc = 1;
+}
+
+/**********************************************************************
+ * Set promiscuous mode
+ **********************************************************************/
+static void
+xlr_mac_set_rx_mode(struct rge_softc *sc)
+{
+ struct driver_data *priv = &(sc->priv);
+ uint32_t regval;
+
+ regval = xlr_read_reg(priv->mmio, R_MAC_FILTER_CONFIG);
+
+ if (sc->flags & IFF_PROMISC) {
+ regval |= (1 << O_MAC_FILTER_CONFIG__BROADCAST_EN) |
+ (1 << O_MAC_FILTER_CONFIG__PAUSE_FRAME_EN) |
+ (1 << O_MAC_FILTER_CONFIG__ALL_MCAST_EN) |
+ (1 << O_MAC_FILTER_CONFIG__ALL_UCAST_EN);
+ } else {
+ regval &= ~((1 << O_MAC_FILTER_CONFIG__PAUSE_FRAME_EN) |
+ (1 << O_MAC_FILTER_CONFIG__ALL_UCAST_EN));
+ }
+
+ xlr_write_reg(priv->mmio, R_MAC_FILTER_CONFIG, regval);
+}
+
+/**********************************************************************
+ * Configure LAN speed for the specified MAC.
+ ********************************************************************* */
+static int
+rmi_xlr_mac_set_speed(struct driver_data *s, xlr_mac_speed_t speed)
+{
+ return 0;
+}
+
+/**********************************************************************
+ * Set Ethernet duplex and flow control options for this MAC
+ ********************************************************************* */
+static int
+rmi_xlr_mac_set_duplex(struct driver_data *s,
+ xlr_mac_duplex_t duplex, xlr_mac_fc_t fc)
+{
+ return 0;
+}
+
+/*****************************************************************
+ * Kernel Net Stack <-> MAC Driver Interface
+ *****************************************************************/
+/**********************************************************************
+ **********************************************************************/
+#define MAC_TX_FAIL 2
+#define MAC_TX_PASS 0
+#define MAC_TX_RETRY 1
+
+static __inline__ void
+message_send_block(unsigned int size, unsigned int code,
+ unsigned int stid, struct msgrng_msg *msg)
+{
+ unsigned int dest = 0;
+ unsigned long long status = 0;
+
+ msgrng_load_tx_msg0(msg->msg0);
+ msgrng_load_tx_msg1(msg->msg1);
+ msgrng_load_tx_msg2(msg->msg2);
+ msgrng_load_tx_msg3(msg->msg3);
+
+ dest = ((size - 1) << 16) | (code << 8) | (stid);
+
+ do {
+ msgrng_send(dest);
+ status = msgrng_read_status();
+ } while (status & 0x6);
+
+}
+
+int xlr_dev_queue_xmit_hack = 0;
+
+static int
+mac_xmit(struct mbuf *m, struct rge_softc *sc,
+ struct driver_data *priv, int len, struct p2d_tx_desc *tx_desc)
+{
+ struct msgrng_msg msg;
+ int stid = priv->txbucket;
+ uint32_t tx_cycles = 0;
+ unsigned long mflags = 0;
+ int vcpu = PCPU_GET(cpuid);
+ int rv;
+
+ tx_cycles = mips_rd_count();
+
+ if (build_frag_list(m, &msg, tx_desc) != 0)
+ return MAC_TX_FAIL;
+
+ else {
+ msgrng_access_enable(mflags);
+ if ((rv = message_send_retry(1, MSGRNG_CODE_MAC, stid, &msg)) != 0) {
+ msg_snd_failed++;
+ msgrng_access_disable(mflags);
+ release_tx_desc(&msg, 0);
+ xlr_rge_msg_snd_failed[vcpu]++;
+ dbg_msg("Failed packet to cpu %d, rv = %d, stid %d, msg0=%llx\n",
+ vcpu, rv, stid, msg.msg0);
+ return MAC_TX_FAIL;
+ }
+ msgrng_access_disable(mflags);
+ port_inc_counter(priv->instance, PORT_TX);
+ }
+
+ /* Send the packet to MAC */
+ dbg_msg("Sent tx packet to stid %d, msg0=%llx, msg1=%llx \n", stid, msg.msg0, msg.msg1);
+#ifdef DUMP_PACKETS
+ {
+ int i = 0;
+ unsigned char *buf = (char *)m->m_data;
+
+ printf("Tx Packet: length=%d\n", len);
+ for (i = 0; i < 64; i++) {
+ if (i && (i % 16) == 0)
+ printf("\n");
+ printf("%02x ", buf[i]);
+ }
+ printf("\n");
+ }
+#endif
+ xlr_inc_counter(NETIF_TX);
+ return MAC_TX_PASS;
+}
+
+static int
+rmi_xlr_mac_xmit(struct mbuf *m, struct rge_softc *sc, int len, struct p2d_tx_desc *tx_desc)
+{
+ struct driver_data *priv = &(sc->priv);
+ int ret = -ENOSPC;
+
+ dbg_msg("IN\n");
+
+ xlr_inc_counter(NETIF_STACK_TX);
+
+retry:
+ ret = mac_xmit(m, sc, priv, len, tx_desc);
+
+ if (ret == MAC_TX_RETRY)
+ goto retry;
+
+ dbg_msg("OUT, ret = %d\n", ret);
+ if (ret == MAC_TX_FAIL) {
+ /* FULL */
+ dbg_msg("Msg Ring Full. Stopping upper layer Q\n");
+ port_inc_counter(priv->instance, PORT_STOPQ);
+ }
+ return ret;
+}
+
+static void
+mac_frin_replenish(void *args /* ignored */ )
+{
+#ifdef RX_COPY
+ return;
+#else
+ int cpu = xlr_cpu_id();
+ int done = 0;
+ int i = 0;
+
+ xlr_inc_counter(REPLENISH_ENTER);
+ /*
+ * xlr_set_counter(REPLENISH_ENTER_COUNT,
+ * atomic_read(frin_to_be_sent));
+ */
+ xlr_set_counter(REPLENISH_CPU, PCPU_GET(cpuid));
+
+ for (;;) {
+
+ done = 0;
+
+ for (i = 0; i < XLR_MAX_MACS; i++) {
+ /* int offset = 0; */
+ unsigned long msgrng_flags;
+ void *m;
+ uint32_t cycles;
+ struct rge_softc *sc;
+ struct driver_data *priv;
+ int frin_to_be_sent;
+
+ sc = dev_mac[i];
+ if (!sc)
+ goto skip;
+
+ priv = &(sc->priv);
+ frin_to_be_sent = priv->frin_to_be_sent[cpu];
+
+ /* if (atomic_read(frin_to_be_sent) < 0) */
+ if (frin_to_be_sent < 0) {
+ panic("BUG?: [%s]: gmac_%d illegal value for frin_to_be_sent=%d\n",
+ __FUNCTION__, i,
+ frin_to_be_sent);
+ }
+ /* if (!atomic_read(frin_to_be_sent)) */
+ if (!frin_to_be_sent)
+ goto skip;
+
+ cycles = mips_rd_count();
+ {
+ m = get_buf();
+ if (!m) {
+ device_printf(sc->rge_dev, "No buffer\n");
+ goto skip;
+ }
+ }
+ xlr_inc_counter(REPLENISH_FRIN);
+ msgrng_access_enable(msgrng_flags);
+ if (xlr_mac_send_fr(priv, vtophys(m), MAX_FRAME_SIZE)) {
+ free_buf(vtophys(m));
+ printf("[%s]: rx free message_send failed!\n", __FUNCTION__);
+ msgrng_access_disable(msgrng_flags);
+ break;
+ }
+ msgrng_access_disable(msgrng_flags);
+ xlr_set_counter(REPLENISH_CYCLES,
+ (read_c0_count() - cycles));
+ atomic_subtract_int((&priv->frin_to_be_sent[cpu]), 1);
+
+ continue;
+ skip:
+ done++;
+ }
+ if (done == XLR_MAX_MACS)
+ break;
+ }
+#endif
+}
+
+static volatile uint32_t g_tx_frm_tx_ok;
+
+static void
+rge_tx_bkp_func(void *arg, int npending)
+{
+ int i = 0;
+
+ for (i = 0; i < xlr_board_info.gmacports; i++) {
+ if (!dev_mac[i] || !dev_mac[i]->active)
+ continue;
+ rge_start_locked(dev_mac[i]->rge_ifp, RGE_TX_THRESHOLD);
+ }
+ atomic_subtract_int(&g_tx_frm_tx_ok, 1);
+}
+
+/* This function is called from an interrupt handler */
+void
+rmi_xlr_mac_msgring_handler(int bucket, int size, int code,
+ int stid, struct msgrng_msg *msg,
+ void *data /* ignored */ )
+{
+ uint64_t phys_addr = 0;
+ unsigned long addr = 0;
+ uint32_t length = 0;
+ int ctrl = 0, port = 0;
+ struct rge_softc *sc = NULL;
+ struct driver_data *priv = 0;
+ struct ifnet *ifp;
+ int cpu = xlr_cpu_id();
+ int vcpu = (cpu << 2) + xlr_thr_id();
+
+ dbg_msg("mac: bucket=%d, size=%d, code=%d, stid=%d, msg0=%llx msg1=%llx\n",
+ bucket, size, code, stid, msg->msg0, msg->msg1);
+
+ phys_addr = (uint64_t) (msg->msg0 & 0xffffffffe0ULL);
+ length = (msg->msg0 >> 40) & 0x3fff;
+ if (length == 0) {
+ ctrl = CTRL_REG_FREE;
+ port = (msg->msg0 >> 54) & 0x0f;
+ addr = 0;
+ } else {
+ ctrl = CTRL_SNGL;
+ length = length - BYTE_OFFSET - MAC_CRC_LEN;
+ port = msg->msg0 & 0x0f;
+ addr = 0;
+ }
+
+ if (xlr_board_info.is_xls) {
+ if (stid == MSGRNG_STNID_GMAC1)
+ port += 4;
+ sc = dev_mac[dev_mac_gmac0 + port];
+ } else {
+ if (stid == MSGRNG_STNID_XGS0FR)
+ sc = dev_mac[dev_mac_xgs0];
+ else if (stid == MSGRNG_STNID_XGS1FR)
+ sc = dev_mac[dev_mac_xgs0 + 1];
+ else
+ sc = dev_mac[dev_mac_gmac0 + port];
+ }
+ if (sc == NULL)
+ return;
+ priv = &(sc->priv);
+
+ dbg_msg("msg0 = %llx, stid = %d, port = %d, addr=%lx, length=%d, ctrl=%d\n",
+ msg->msg0, stid, port, addr, length, ctrl);
+
+ if (ctrl == CTRL_REG_FREE || ctrl == CTRL_JUMBO_FREE) {
+ xlr_rge_tx_ok_done[vcpu]++;
+ release_tx_desc(msg, 1);
+ ifp = sc->rge_ifp;
+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ }
+ if (atomic_cmpset_int(&g_tx_frm_tx_ok, 0, 1))
+ rge_tx_bkp_func(NULL, 0);
+ xlr_set_counter(NETIF_TX_COMPLETE_CYCLES,
+ (read_c0_count() - msgrng_msg_cycles));
+ } else if (ctrl == CTRL_SNGL || ctrl == CTRL_START) {
+ /* Rx Packet */
+ /* struct mbuf *m = 0; */
+ /* int logical_cpu = 0; */
+
+ dbg_msg("Received packet, port = %d\n", port);
+ /*
+ * if num frins to be sent exceeds threshold, wake up the
+ * helper thread
+ */
+ atomic_add_int(&(priv->frin_to_be_sent[cpu]), 1);
+ if ((priv->frin_to_be_sent[cpu]) > MAC_FRIN_TO_BE_SENT_THRESHOLD) {
+ mac_frin_replenish(NULL);
+ }
+ dbg_msg("gmac_%d: rx packet: phys_addr = %llx, length = %x\n",
+ priv->instance, phys_addr, length);
+ mac_stats_add(priv->stats.rx_packets, 1);
+ mac_stats_add(priv->stats.rx_bytes, length);
+ xlr_inc_counter(NETIF_RX);
+ xlr_set_counter(NETIF_RX_CYCLES,
+ (read_c0_count() - msgrng_msg_cycles));
+ rge_rx(sc, phys_addr, length);
+ xlr_rge_rx_done[vcpu]++;
+ } else {
+ printf("[%s]: unrecognized ctrl=%d!\n", __FUNCTION__, ctrl);
+ }
+
+}
+
+/**********************************************************************
+ **********************************************************************/
+static int
+rge_probe(dev)
+ device_t dev;
+{
+ /* Always return 0 */
+ return 0;
+}
+
+volatile unsigned long xlr_debug_enabled;
+struct callout rge_dbg_count;
+static void
+xlr_debug_count(void *addr)
+{
+ struct driver_data *priv = &dev_mac[0]->priv;
+
+ /* uint32_t crdt; */
+ if (xlr_debug_enabled) {
+ printf("\nAvailRxIn %#x\n", xlr_read_reg(priv->mmio, 0x23e));
+ }
+ callout_reset(&rge_dbg_count, hz, xlr_debug_count, NULL);
+}
+
+
+static void
+xlr_tx_q_wakeup(void *addr)
+{
+ int i = 0;
+ int j = 0;
+
+ for (i = 0; i < xlr_board_info.gmacports; i++) {
+ if (!dev_mac[i] || !dev_mac[i]->active)
+ continue;
+ if ((dev_mac[i]->rge_ifp->if_drv_flags) & IFF_DRV_OACTIVE) {
+ for (j = 0; j < XLR_MAX_CORE; j++) {
+ if (xlr_tot_avail_p2d[j]) {
+ dev_mac[i]->rge_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ break;
+ }
+ }
+ }
+ }
+ callout_reset(&xlr_tx_stop_bkp, 5 * hz, xlr_tx_q_wakeup, NULL);
+}
+
+static int
+rge_attach(device_t dev)
+{
+ struct ifnet *ifp;
+ struct rge_softc *sc;
+ struct driver_data *priv = 0;
+ int ret = 0;
+ struct xlr_gmac_block_t *gmac_conf = device_get_ivars(dev);
+
+ sc = device_get_softc(dev);
+ sc->rge_dev = dev;
+
+ /* Initialize mac's */
+ sc->unit = device_get_unit(dev);
+
+ if (sc->unit > XLR_MAX_MACS) {
+ ret = ENXIO;
+ goto out;
+ }
+ RGE_LOCK_INIT(sc, device_get_nameunit(dev));
+
+ priv = &(sc->priv);
+ priv->sc = sc;
+
+ sc->flags = 0; /* TODO : fix me up later */
+
+ priv->id = sc->unit;
+ if (gmac_conf->type == XLR_GMAC) {
+ priv->instance = priv->id;
+ priv->mmio = (xlr_reg_t *) (xlr_io_base + gmac_conf->baseaddr +
+ 0x1000 * (sc->unit % 4));
+ if ((ret = rmi_xlr_gmac_reset(priv)) == -1)
+ goto out;
+ } else if (gmac_conf->type == XLR_XGMAC) {
+ priv->instance = priv->id - xlr_board_info.gmacports;
+ priv->mmio = (xlr_reg_t *) (xlr_io_base + gmac_conf->baseaddr);
+ }
+ if (xlr_boot1_info.board_major_version == RMI_XLR_BOARD_ARIZONA_VI) {
+ dbg_msg("Arizona board - offset 4 \n");
+ priv->mii_mmio = (xlr_reg_t *) (xlr_io_base + XLR_IO_GMAC_4_OFFSET);
+ } else
+ priv->mii_mmio = (xlr_reg_t *) (xlr_io_base + XLR_IO_GMAC_0_OFFSET);
+
+ priv->pcs_mmio = (xlr_reg_t *) (xlr_io_base + gmac_conf->baseaddr);
+ priv->serdes_mmio = (xlr_reg_t *) (xlr_io_base + XLR_IO_GMAC_0_OFFSET);
+
+ sc->base_addr = (unsigned long)priv->mmio;
+ sc->mem_end = (unsigned long)priv->mmio + XLR_IO_SIZE - 1;
+
+ sc->xmit = rge_start;
+ sc->stop = rge_stop;
+ sc->get_stats = rmi_xlr_mac_get_stats;
+ sc->ioctl = rge_ioctl;
+
+ /* Initialize the device specific driver data */
+ mtx_init(&priv->lock, "rge", NULL, MTX_SPIN);
+
+ priv->type = gmac_conf->type;
+
+ priv->mode = gmac_conf->mode;
+ if (xlr_board_info.is_xls == 0) {
+ if (xlr_board_atx_ii() && !xlr_board_atx_ii_b())
+ priv->phy_addr = priv->instance - 2;
+ else
+ priv->phy_addr = priv->instance;
+ priv->mode = XLR_RGMII;
+ } else {
+ if (gmac_conf->mode == XLR_PORT0_RGMII &&
+ priv->instance == 0) {
+ priv->mode = XLR_PORT0_RGMII;
+ priv->phy_addr = 0;
+ } else {
+ priv->mode = XLR_SGMII;
+ priv->phy_addr = priv->instance + 16;
+ }
+ }
+
+ priv->txbucket = gmac_conf->station_txbase + priv->instance % 4;
+ priv->rfrbucket = gmac_conf->station_rfr;
+ priv->spill_configured = 0;
+
+ dbg_msg("priv->mmio=%p\n", priv->mmio);
+
+ /* Set up ifnet structure */
+ ifp = sc->rge_ifp = if_alloc(IFT_ETHER);
+ if (ifp == NULL) {
+ device_printf(sc->rge_dev, "failed to if_alloc()\n");
+ rge_release_resources(sc);
+ ret = ENXIO;
+ RGE_LOCK_DESTROY(sc);
+ goto out;
+ }
+ ifp->if_softc = sc;
+ if_initname(ifp, device_get_name(dev), device_get_unit(dev));
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = rge_ioctl;
+ ifp->if_start = rge_start;
+ ifp->if_watchdog = rge_watchdog;
+ ifp->if_init = rge_init;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_snd.ifq_drv_maxlen = RGE_TX_Q_SIZE;
+ IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
+ IFQ_SET_READY(&ifp->if_snd);
+ sc->active = 1;
+ ifp->if_hwassist = 0;
+ ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_VLAN_HWTAGGING;
+ ifp->if_capenable = ifp->if_capabilities;
+
+ /* Initialize the rge_softc */
+ sc->irq = gmac_conf->baseirq + priv->instance % 4;
+
+ /* Set the IRQ into the rid field */
+ /*
+ * note this is a hack to pass the irq to the iodi interrupt setup
+ * routines
+ */
+ sc->rge_irq.__r_i = (struct resource_i *)sc->irq;
+
+ ret = bus_setup_intr(dev, &sc->rge_irq, INTR_FAST | INTR_TYPE_NET | INTR_MPSAFE,
+ NULL, rge_intr, sc, &sc->rge_intrhand);
+
+ if (ret) {
+ rge_detach(dev);
+ device_printf(sc->rge_dev, "couldn't set up irq\n");
+ RGE_LOCK_DESTROY(sc);
+ goto out;
+ }
+ xlr_mac_get_hwaddr(sc);
+ xlr_mac_setup_hwaddr(priv);
+
+ dbg_msg("MMIO %08lx, MII %08lx, PCS %08lx, base %08lx PHY %d IRQ %d\n",
+ (u_long)priv->mmio, (u_long)priv->mii_mmio, (u_long)priv->pcs_mmio,
+ (u_long)sc->base_addr, priv->phy_addr, sc->irq);
+ dbg_msg("HWADDR %02x:%02x tx %d rfr %d\n", (u_int)sc->dev_addr[4],
+ (u_int)sc->dev_addr[5], priv->txbucket, priv->rfrbucket);
+
+ /*
+ * Set up ifmedia support.
+ */
+ /*
+ * Initialize MII/media info.
+ */
+ sc->rge_mii.mii_ifp = ifp;
+ sc->rge_mii.mii_readreg = rge_mii_read;
+ sc->rge_mii.mii_writereg = (mii_writereg_t) rge_mii_write;
+ sc->rge_mii.mii_statchg = rmi_xlr_mac_mii_statchg;
+ ifmedia_init(&sc->rge_mii.mii_media, 0, rmi_xlr_mac_mediachange,
+ rmi_xlr_mac_mediastatus);
+ ifmedia_add(&sc->rge_mii.mii_media, IFM_ETHER | IFM_AUTO, 0, NULL);
+ ifmedia_set(&sc->rge_mii.mii_media, IFM_ETHER | IFM_AUTO);
+ sc->rge_mii.mii_media.ifm_media = sc->rge_mii.mii_media.ifm_cur->ifm_media;
+
+ /*
+ * Call MI attach routine.
+ */
+ ether_ifattach(ifp, sc->dev_addr);
+
+ if (priv->type == XLR_GMAC) {
+ rmi_xlr_gmac_init(priv);
+ } else if (priv->type == XLR_XGMAC) {
+ rmi_xlr_xgmac_init(priv);
+ }
+ dbg_msg("rge_%d: Phoenix Mac at 0x%p (mtu=%d)\n",
+ sc->unit, priv->mmio, sc->mtu);
+ dev_mac[sc->unit] = sc;
+ if (priv->type == XLR_XGMAC && priv->instance == 0)
+ dev_mac_xgs0 = sc->unit;
+ if (priv->type == XLR_GMAC && priv->instance == 0)
+ dev_mac_gmac0 = sc->unit;
+
+ if (!gmac_common_init_done) {
+ mac_common_init();
+ gmac_common_init_done = 1;
+ callout_init(&xlr_tx_stop_bkp, CALLOUT_MPSAFE);
+ callout_reset(&xlr_tx_stop_bkp, hz, xlr_tx_q_wakeup, NULL);
+ callout_init(&rge_dbg_count, CALLOUT_MPSAFE);
+ //callout_reset(&rge_dbg_count, hz, xlr_debug_count, NULL);
+ }
+ if ((ret = rmi_xlr_mac_open(sc)) == -1) {
+ RGE_LOCK_DESTROY(sc);
+ goto out;
+ }
+out:
+ if (ret < 0) {
+ device_printf(dev, "error - skipping\n");
+ }
+ return ret;
+}
+
+static void
+rge_reset(struct rge_softc *sc)
+{
+}
+
+static int
+rge_detach(dev)
+ device_t dev;
+{
+#ifdef FREEBSD_MAC_NOT_YET
+ struct rge_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ ifp = sc->rge_ifp;
+
+ RGE_LOCK(sc);
+ rge_stop(sc);
+ rge_reset(sc);
+ RGE_UNLOCK(sc);
+
+ ether_ifdetach(ifp);
+
+ if (sc->rge_tbi) {
+ ifmedia_removeall(&sc->rge_ifmedia);
+ } else {
+ bus_generic_detach(dev);
+ device_delete_child(dev, sc->rge_miibus);
+ }
+
+ rge_release_resources(sc);
+
+#endif /* FREEBSD_MAC_NOT_YET */
+ return (0);
+}
+static int
+rge_suspend(device_t dev)
+{
+ struct rge_softc *sc;
+
+ sc = device_get_softc(dev);
+ RGE_LOCK(sc);
+ rge_stop(sc);
+ RGE_UNLOCK(sc);
+
+ return 0;
+}
+
+static int
+rge_resume(device_t dev)
+{
+ panic("rge_resume(): unimplemented\n");
+ return 0;
+}
+
+static void
+rge_release_resources(struct rge_softc *sc)
+{
+
+ if (sc->rge_ifp != NULL)
+ if_free(sc->rge_ifp);
+
+ if (mtx_initialized(&sc->rge_mtx)) /* XXX */
+ RGE_LOCK_DESTROY(sc);
+}
+uint32_t gmac_rx_fail[32];
+uint32_t gmac_rx_pass[32];
+
+#ifdef RX_COPY
+static void
+rge_rx(struct rge_softc *sc, vm_paddr_t paddr, int len)
+{
+ /*
+ * struct mbuf *m = (struct mbuf *)*(unsigned int *)((char *)addr -
+ * XLR_CACHELINE_SIZE);
+ */
+ struct mbuf *m;
+ void *ptr;
+ uint32_t *temp;
+ struct ifnet *ifp = sc->rge_ifp;
+ unsigned long msgrng_flags;
+ int cpu = PCPU_GET(cpuid);
+
+
+ temp = (uint32_t *) MIPS_PHYS_TO_KSEG0(paddr - XLR_CACHELINE_SIZE);
+
+ ptr = (void *)(temp + XLR_CACHELINE_SIZE);
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m != NULL) {
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+ m_copyback(m, 0, len + BYTE_OFFSET, ptr);
+ /* align the data */
+ m->m_data += BYTE_OFFSET;
+ m->m_pkthdr.len = m->m_len = len;
+ m->m_pkthdr.rcvif = ifp;
+ gmac_rx_pass[cpu]++;
+ } else {
+ gmac_rx_fail[cpu]++;
+ }
+ msgrng_access_enable(msgrng_flags);
+ xlr_mac_send_fr(&sc->priv, paddr, MAX_FRAME_SIZE);
+ msgrng_access_disable(msgrng_flags);
+
+#ifdef DUMP_PACKETS
+ {
+ int i = 0;
+ unsigned char *buf = (char *)m->m_data;
+
+ printf("Rx Packet: length=%d\n", len);
+ for (i = 0; i < 64; i++) {
+ if (i && (i % 16) == 0)
+ printf("\n");
+ printf("%02x ", buf[i]);
+ }
+ printf("\n");
+ }
+#endif
+
+
+ if (m) {
+ ifp->if_ipackets++;
+ (*ifp->if_input) (ifp, m);
+ }
+}
+
+#else
+static void
+rge_rx(struct rge_softc *sc, vm_paddr_t paddr, int len)
+{
+ /*
+ * struct mbuf *m = (struct mbuf *)*(unsigned int *)((char *)addr -
+ * XLR_CACHELINE_SIZE);
+ */
+ struct mbuf *m;
+ uint32_t *temp, tm, mag;
+
+ struct ifnet *ifp = sc->rge_ifp;
+
+
+ temp = (uint32_t *) MIPS_PHYS_TO_KSEG0(paddr - XLR_CACHELINE_SIZE);
+ tm = temp[0];
+ mag = temp[1];
+ m = (struct mbuf *)tm;
+ if (mag != 0xf00bad) {
+ /* somebody else packet Error - FIXME in intialization */
+ printf("cpu %d: *ERROR* Not my packet paddr %p\n", xlr_cpu_id(), (void *)paddr);
+ return;
+ }
+ /* align the data */
+ m->m_data += BYTE_OFFSET;
+ m->m_pkthdr.len = m->m_len = len;
+ m->m_pkthdr.rcvif = ifp;
+
+#ifdef DUMP_PACKETS
+ {
+ int i = 0;
+ unsigned char *buf = (char *)m->m_data;
+
+ printf("Rx Packet: length=%d\n", len);
+ for (i = 0; i < 64; i++) {
+ if (i && (i % 16) == 0)
+ printf("\n");
+ printf("%02x ", buf[i]);
+ }
+ printf("\n");
+ }
+#endif
+ ifp->if_ipackets++;
+ (*ifp->if_input) (ifp, m);
+}
+
+#endif
+
+static void
+rge_intr(void *arg)
+{
+ struct rge_softc *sc = (struct rge_softc *)arg;
+ struct driver_data *priv = &(sc->priv);
+ xlr_reg_t *mmio = priv->mmio;
+ uint32_t intreg = xlr_read_reg(mmio, R_INTREG);
+
+ if (intreg & (1 << O_INTREG__MDInt)) {
+ uint32_t phy_int_status = 0;
+ int i = 0;
+
+ for (i = 0; i < XLR_MAX_MACS; i++) {
+ struct rge_softc *phy_dev = 0;
+ struct driver_data *phy_priv = 0;
+
+ phy_dev = dev_mac[i];
+ if (phy_dev == NULL)
+ continue;
+
+ phy_priv = &phy_dev->priv;
+
+ if (phy_priv->type == XLR_XGMAC)
+ continue;
+
+ phy_int_status = rge_mii_read_internal(phy_priv->mii_mmio,
+ phy_priv->phy_addr, 26);
+ printf("rge%d: Phy addr %d, MII MMIO %lx status %x\n", phy_priv->instance,
+ (int)phy_priv->phy_addr, (u_long)phy_priv->mii_mmio, phy_int_status);
+ rmi_xlr_gmac_config_speed(phy_priv);
+ }
+ } else {
+ printf("[%s]: mac type = %d, instance %d error "
+ "interrupt: INTREG = 0x%08x\n",
+ __FUNCTION__, priv->type, priv->instance, intreg);
+ }
+
+ /* clear all interrupts and hope to make progress */
+ xlr_write_reg(mmio, R_INTREG, 0xffffffff);
+
+ /* on A0 and B0, xgmac interrupts are routed only to xgs_1 irq */
+ if ((xlr_revision_b0()) && (priv->type == XLR_XGMAC)) {
+ struct rge_softc *xgs0_dev = dev_mac[dev_mac_xgs0];
+ struct driver_data *xgs0_priv = &xgs0_dev->priv;
+ xlr_reg_t *xgs0_mmio = xgs0_priv->mmio;
+ uint32_t xgs0_intreg = xlr_read_reg(xgs0_mmio, R_INTREG);
+
+ if (xgs0_intreg) {
+ printf("[%s]: mac type = %d, instance %d error "
+ "interrupt: INTREG = 0x%08x\n",
+ __FUNCTION__, xgs0_priv->type, xgs0_priv->instance, xgs0_intreg);
+
+ xlr_write_reg(xgs0_mmio, R_INTREG, 0xffffffff);
+ }
+ }
+}
+
+static void
+rge_start_locked(struct ifnet *ifp, int threshold)
+{
+ struct rge_softc *sc = ifp->if_softc;
+ struct mbuf *m = NULL;
+ int prepend_pkt = 0;
+ int i = 0;
+ struct p2d_tx_desc *tx_desc = NULL;
+ int cpu = xlr_cpu_id();
+ uint32_t vcpu = (cpu << 2) + xlr_thr_id();
+
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ return;
+
+ for (i = 0; i < xlr_tot_avail_p2d[cpu]; i++) {
+ if (IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ return;
+ tx_desc = get_p2d_desc();
+ if (!tx_desc) {
+ xlr_rge_get_p2d_failed[vcpu]++;
+ return;
+ }
+ /* Grab a packet off the queue. */
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL) {
+ free_p2d_desc(tx_desc);
+ return;
+ }
+ prepend_pkt = rmi_xlr_mac_xmit(m, sc, 0, tx_desc);
+
+ if (prepend_pkt) {
+ xlr_rge_tx_prepend[vcpu]++;
+ IF_PREPEND(&ifp->if_snd, m);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ return;
+ } else {
+ ifp->if_opackets++;
+ xlr_rge_tx_done[vcpu]++;
+ }
+ }
+}
+
+static void
+rge_start(struct ifnet *ifp)
+{
+ rge_start_locked(ifp, RGE_TX_Q_SIZE);
+}
+
+static int
+rge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct rge_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int mask, error = 0;
+
+ /* struct mii_data *mii; */
+ switch (command) {
+ case SIOCSIFMTU:
+ ifp->if_mtu = ifr->ifr_mtu;
+ error = rmi_xlr_mac_change_mtu(sc, ifr->ifr_mtu);
+ break;
+ case SIOCSIFFLAGS:
+
+ RGE_LOCK(sc);
+ if (ifp->if_flags & IFF_UP) {
+ /*
+ * If only the state of the PROMISC flag changed,
+ * then just use the 'set promisc mode' command
+ * instead of reinitializing the entire NIC. Doing a
+ * full re-init means reloading the firmware and
+ * waiting for it to start up, which may take a
+ * second or two. Similarly for ALLMULTI.
+ */
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->flags & IFF_PROMISC)) {
+ sc->flags |= IFF_PROMISC;
+ xlr_mac_set_rx_mode(sc);
+ } else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->flags & IFF_PROMISC) {
+ sc->flags &= IFF_PROMISC;
+ xlr_mac_set_rx_mode(sc);
+ } else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
+ (ifp->if_flags ^ sc->flags) & IFF_ALLMULTI) {
+ rmi_xlr_mac_set_multicast_list(sc);
+ } else
+ xlr_mac_set_rx_mode(sc);
+ } else {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ xlr_mac_set_rx_mode(sc);
+ }
+ }
+ sc->flags = ifp->if_flags;
+ RGE_UNLOCK(sc);
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ RGE_LOCK(sc);
+ rmi_xlr_mac_set_multicast_list(sc);
+ RGE_UNLOCK(sc);
+ error = 0;
+ }
+ break;
+ case SIOCSIFMEDIA:
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr,
+ &sc->rge_mii.mii_media, command);
+ break;
+ case SIOCSIFCAP:
+ mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+ ifp->if_hwassist = 0;
+ break;
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ return (error);
+}
+
+static void
+rge_init(void *addr)
+{
+ struct rge_softc *sc = (struct rge_softc *)addr;
+ struct ifnet *ifp;
+ struct driver_data *priv = &(sc->priv);
+
+ ifp = sc->rge_ifp;
+
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ return;
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ rmi_xlr_mac_set_enable(priv, 1);
+}
+
+static void
+rge_stop(struct rge_softc *sc)
+{
+ rmi_xlr_mac_close(sc);
+}
+
+static void
+rge_watchdog(struct ifnet *sc)
+{
+}
+
+static int
+rge_shutdown(device_t dev)
+{
+ struct rge_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ RGE_LOCK(sc);
+ rge_stop(sc);
+ rge_reset(sc);
+ RGE_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+rmi_xlr_mac_open(struct rge_softc *sc)
+{
+ struct driver_data *priv = &(sc->priv);
+ int i;
+
+ dbg_msg("IN\n");
+
+ if (rmi_xlr_mac_fill_rxfr(sc)) {
+ return -1;
+ }
+ mtx_lock_spin(&priv->lock);
+
+ xlr_mac_set_rx_mode(sc);
+
+ if (sc->unit == xlr_board_info.gmacports - 1) {
+ printf("Enabling MDIO interrupts\n");
+ struct rge_softc *tmp = NULL;
+
+ for (i = 0; i < xlr_board_info.gmacports; i++) {
+ tmp = dev_mac[i];
+ if (tmp)
+ xlr_write_reg(tmp->priv.mmio, R_INTMASK,
+ ((tmp->priv.instance == 0) << O_INTMASK__MDInt));
+ }
+ }
+ /*
+ * Configure the speed, duplex, and flow control
+ */
+ rmi_xlr_mac_set_speed(priv, priv->speed);
+ rmi_xlr_mac_set_duplex(priv, priv->duplex, priv->flow_ctrl);
+ rmi_xlr_mac_set_enable(priv, 0);
+
+ mtx_unlock_spin(&priv->lock);
+
+ for (i = 0; i < 8; i++) {
+ atomic_set_int(&(priv->frin_to_be_sent[i]), 0);
+ }
+
+ return 0;
+}
+
+/**********************************************************************
+ **********************************************************************/
+static int
+rmi_xlr_mac_close(struct rge_softc *sc)
+{
+ struct driver_data *priv = &(sc->priv);
+
+ mtx_lock_spin(&priv->lock);
+
+ /*
+ * There may have left over mbufs in the ring as well as in free in
+ * they will be reused next time open is called
+ */
+
+ rmi_xlr_mac_set_enable(priv, 0);
+
+ xlr_inc_counter(NETIF_STOP_Q);
+ port_inc_counter(priv->instance, PORT_STOPQ);
+
+ mtx_unlock_spin(&priv->lock);
+
+ return 0;
+}
+
+/**********************************************************************
+ **********************************************************************/
+static struct rge_softc_stats *
+rmi_xlr_mac_get_stats(struct rge_softc *sc)
+{
+ struct driver_data *priv = &(sc->priv);
+
+ /* unsigned long flags; */
+
+ mtx_lock_spin(&priv->lock);
+
+ /* XXX update other stats here */
+
+ mtx_unlock_spin(&priv->lock);
+
+ return &priv->stats;
+}
+
+/**********************************************************************
+ **********************************************************************/
+static void
+rmi_xlr_mac_set_multicast_list(struct rge_softc *sc)
+{
+}
+
+/**********************************************************************
+ **********************************************************************/
+static int
+rmi_xlr_mac_change_mtu(struct rge_softc *sc, int new_mtu)
+{
+ struct driver_data *priv = &(sc->priv);
+
+ if ((new_mtu > 9500) || (new_mtu < 64)) {
+ return -EINVAL;
+ }
+ mtx_lock_spin(&priv->lock);
+
+ sc->mtu = new_mtu;
+
+ /* Disable MAC TX/RX */
+ rmi_xlr_mac_set_enable(priv, 0);
+
+ /* Flush RX FR IN */
+ /* Flush TX IN */
+ rmi_xlr_mac_set_enable(priv, 1);
+
+ mtx_unlock_spin(&priv->lock);
+ return 0;
+}
+
+/**********************************************************************
+ **********************************************************************/
+static int
+rmi_xlr_mac_fill_rxfr(struct rge_softc *sc)
+{
+ struct driver_data *priv = &(sc->priv);
+ unsigned long msgrng_flags;
+ int i;
+ int ret = 0;
+ void *ptr;
+
+ dbg_msg("\n");
+ if (!priv->init_frin_desc)
+ return ret;
+ priv->init_frin_desc = 0;
+
+ dbg_msg("\n");
+ for (i = 0; i < MAX_NUM_DESC; i++) {
+ ptr = get_buf();
+ if (!ptr) {
+ ret = -ENOMEM;
+ break;
+ }
+ /* Send the free Rx desc to the MAC */
+ msgrng_access_enable(msgrng_flags);
+ xlr_mac_send_fr(priv, vtophys(ptr), MAX_FRAME_SIZE);
+ msgrng_access_disable(msgrng_flags);
+ }
+
+ return ret;
+}
+
+/**********************************************************************
+ **********************************************************************/
+static __inline__ void *
+rmi_xlr_config_spill(xlr_reg_t * mmio,
+ int reg_start_0, int reg_start_1,
+ int reg_size, int size)
+{
+ uint32_t spill_size = size;
+ void *spill = NULL;
+ uint64_t phys_addr = 0;
+
+
+ spill = contigmalloc((spill_size + XLR_CACHELINE_SIZE), M_DEVBUF,
+ M_NOWAIT | M_ZERO, 0, 0xffffffff, XLR_CACHELINE_SIZE, 0);
+ if (!spill || ((vm_offset_t)spill & (XLR_CACHELINE_SIZE - 1))) {
+ panic("Unable to allocate memory for spill area!\n");
+ }
+ phys_addr = vtophys(spill);
+ dbg_msg("Allocate spill %d bytes at %llx\n", size, phys_addr);
+ xlr_write_reg(mmio, reg_start_0, (phys_addr >> 5) & 0xffffffff);
+ xlr_write_reg(mmio, reg_start_1, (phys_addr >> 37) & 0x07);
+ xlr_write_reg(mmio, reg_size, spill_size);
+
+ return spill;
+}
+
+static void
+rmi_xlr_config_spill_area(struct driver_data *priv)
+{
+ /*
+ * if driver initialization is done parallely on multiple cpus
+ * spill_configured needs synchronization
+ */
+ if (priv->spill_configured)
+ return;
+
+ if (priv->type == XLR_GMAC && priv->instance % 4 != 0) {
+ priv->spill_configured = 1;
+ return;
+ }
+ priv->spill_configured = 1;
+
+ priv->frin_spill =
+ rmi_xlr_config_spill(priv->mmio,
+ R_REG_FRIN_SPILL_MEM_START_0,
+ R_REG_FRIN_SPILL_MEM_START_1,
+ R_REG_FRIN_SPILL_MEM_SIZE,
+ MAX_FRIN_SPILL *
+ sizeof(struct fr_desc));
+
+ priv->class_0_spill =
+ rmi_xlr_config_spill(priv->mmio,
+ R_CLASS0_SPILL_MEM_START_0,
+ R_CLASS0_SPILL_MEM_START_1,
+ R_CLASS0_SPILL_MEM_SIZE,
+ MAX_CLASS_0_SPILL *
+ sizeof(union rx_tx_desc));
+ priv->class_1_spill =
+ rmi_xlr_config_spill(priv->mmio,
+ R_CLASS1_SPILL_MEM_START_0,
+ R_CLASS1_SPILL_MEM_START_1,
+ R_CLASS1_SPILL_MEM_SIZE,
+ MAX_CLASS_1_SPILL *
+ sizeof(union rx_tx_desc));
+
+ priv->frout_spill =
+ rmi_xlr_config_spill(priv->mmio, R_FROUT_SPILL_MEM_START_0,
+ R_FROUT_SPILL_MEM_START_1,
+ R_FROUT_SPILL_MEM_SIZE,
+ MAX_FROUT_SPILL *
+ sizeof(struct fr_desc));
+
+ priv->class_2_spill =
+ rmi_xlr_config_spill(priv->mmio,
+ R_CLASS2_SPILL_MEM_START_0,
+ R_CLASS2_SPILL_MEM_START_1,
+ R_CLASS2_SPILL_MEM_SIZE,
+ MAX_CLASS_2_SPILL *
+ sizeof(union rx_tx_desc));
+ priv->class_3_spill =
+ rmi_xlr_config_spill(priv->mmio,
+ R_CLASS3_SPILL_MEM_START_0,
+ R_CLASS3_SPILL_MEM_START_1,
+ R_CLASS3_SPILL_MEM_SIZE,
+ MAX_CLASS_3_SPILL *
+ sizeof(union rx_tx_desc));
+ priv->spill_configured = 1;
+}
+
+/*****************************************************************
+ * Write the MAC address to the XLR registers
+ * All 4 addresses are the same for now
+ *****************************************************************/
+static void
+xlr_mac_setup_hwaddr(struct driver_data *priv)
+{
+ struct rge_softc *sc = priv->sc;
+
+ xlr_write_reg(priv->mmio, R_MAC_ADDR0,
+ ((sc->dev_addr[5] << 24) | (sc->dev_addr[4] << 16)
+ | (sc->dev_addr[3] << 8) | (sc->dev_addr[2]))
+ );
+
+ xlr_write_reg(priv->mmio, R_MAC_ADDR0 + 1,
+ ((sc->dev_addr[1] << 24) | (sc->
+ dev_addr[0] << 16)));
+
+ xlr_write_reg(priv->mmio, R_MAC_ADDR_MASK2, 0xffffffff);
+
+ xlr_write_reg(priv->mmio, R_MAC_ADDR_MASK2 + 1, 0xffffffff);
+
+ xlr_write_reg(priv->mmio, R_MAC_ADDR_MASK3, 0xffffffff);
+
+ xlr_write_reg(priv->mmio, R_MAC_ADDR_MASK3 + 1, 0xffffffff);
+
+ xlr_write_reg(priv->mmio, R_MAC_FILTER_CONFIG,
+ (1 << O_MAC_FILTER_CONFIG__BROADCAST_EN) |
+ (1 << O_MAC_FILTER_CONFIG__ALL_MCAST_EN) |
+ (1 << O_MAC_FILTER_CONFIG__MAC_ADDR0_VALID)
+ );
+}
+
+/*****************************************************************
+ * Read the MAC address from the XLR registers
+ * All 4 addresses are the same for now
+ *****************************************************************/
+static void
+xlr_mac_get_hwaddr(struct rge_softc *sc)
+{
+ struct driver_data *priv = &(sc->priv);
+
+ sc->dev_addr[0] = (xlr_boot1_info.mac_addr >> 40) & 0xff;
+ sc->dev_addr[1] = (xlr_boot1_info.mac_addr >> 32) & 0xff;
+ sc->dev_addr[2] = (xlr_boot1_info.mac_addr >> 24) & 0xff;
+ sc->dev_addr[3] = (xlr_boot1_info.mac_addr >> 16) & 0xff;
+ sc->dev_addr[4] = (xlr_boot1_info.mac_addr >> 8) & 0xff;
+ sc->dev_addr[5] = ((xlr_boot1_info.mac_addr >> 0) & 0xff) + priv->instance;
+}
+
+/*****************************************************************
+ * Mac Module Initialization
+ *****************************************************************/
+static void
+mac_common_init(void)
+{
+ init_p2d_allocation();
+ init_tx_ring();
+#ifdef RX_COPY
+ init_rx_buf();
+#endif
+
+ if (xlr_board_info.is_xls) {
+ if (register_msgring_handler(TX_STN_GMAC0,
+ rmi_xlr_mac_msgring_handler, NULL)) {
+ panic("Couldn't register msgring handler\n");
+ }
+ if (register_msgring_handler(TX_STN_GMAC1,
+ rmi_xlr_mac_msgring_handler, NULL)) {
+ panic("Couldn't register msgring handler\n");
+ }
+ } else {
+ if (register_msgring_handler(TX_STN_GMAC,
+ rmi_xlr_mac_msgring_handler, NULL)) {
+ panic("Couldn't register msgring handler\n");
+ }
+ }
+
+ /*
+ * Not yet if (xlr_board_atx_ii()) { if (register_msgring_handler
+ * (TX_STN_XGS_0, rmi_xlr_mac_msgring_handler, NULL)) {
+ * panic("Couldn't register msgring handler for TX_STN_XGS_0\n"); }
+ * if (register_msgring_handler (TX_STN_XGS_1,
+ * rmi_xlr_mac_msgring_handler, NULL)) { panic("Couldn't register
+ * msgring handler for TX_STN_XGS_1\n"); } }
+ */
+}