13c0086b8SZbigniew Bodek /*
23c0086b8SZbigniew Bodek * Copyright (C) 2015 Cavium Inc.
33c0086b8SZbigniew Bodek * All rights reserved.
43c0086b8SZbigniew Bodek *
53c0086b8SZbigniew Bodek * Redistribution and use in source and binary forms, with or without
63c0086b8SZbigniew Bodek * modification, are permitted provided that the following conditions
73c0086b8SZbigniew Bodek * are met:
83c0086b8SZbigniew Bodek * 1. Redistributions of source code must retain the above copyright
93c0086b8SZbigniew Bodek * notice, this list of conditions and the following disclaimer.
103c0086b8SZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright
113c0086b8SZbigniew Bodek * notice, this list of conditions and the following disclaimer in the
123c0086b8SZbigniew Bodek * documentation and/or other materials provided with the distribution.
133c0086b8SZbigniew Bodek *
143c0086b8SZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153c0086b8SZbigniew Bodek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163c0086b8SZbigniew Bodek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173c0086b8SZbigniew Bodek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183c0086b8SZbigniew Bodek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193c0086b8SZbigniew Bodek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203c0086b8SZbigniew Bodek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213c0086b8SZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223c0086b8SZbigniew Bodek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233c0086b8SZbigniew Bodek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243c0086b8SZbigniew Bodek * SUCH DAMAGE.
253c0086b8SZbigniew Bodek *
263c0086b8SZbigniew Bodek */
272306b72aSZbigniew Bodek #include "opt_platform.h"
283c0086b8SZbigniew Bodek
292306b72aSZbigniew Bodek #include <sys/param.h>
302306b72aSZbigniew Bodek #include <sys/systm.h>
312306b72aSZbigniew Bodek #include <sys/bitset.h>
322306b72aSZbigniew Bodek #include <sys/bitstring.h>
332306b72aSZbigniew Bodek #include <sys/bus.h>
342306b72aSZbigniew Bodek #include <sys/endian.h>
352306b72aSZbigniew Bodek #include <sys/kernel.h>
362306b72aSZbigniew Bodek #include <sys/malloc.h>
372306b72aSZbigniew Bodek #include <sys/module.h>
382306b72aSZbigniew Bodek #include <sys/rman.h>
392306b72aSZbigniew Bodek #include <sys/pciio.h>
402306b72aSZbigniew Bodek #include <sys/pcpu.h>
412306b72aSZbigniew Bodek #include <sys/proc.h>
422306b72aSZbigniew Bodek #include <sys/socket.h>
432306b72aSZbigniew Bodek #include <sys/sockio.h>
442306b72aSZbigniew Bodek #include <sys/cpuset.h>
452306b72aSZbigniew Bodek #include <sys/lock.h>
462306b72aSZbigniew Bodek #include <sys/mutex.h>
472306b72aSZbigniew Bodek
482306b72aSZbigniew Bodek #include <net/ethernet.h>
492306b72aSZbigniew Bodek #include <net/if.h>
502306b72aSZbigniew Bodek #include <net/if_media.h>
512306b72aSZbigniew Bodek
522306b72aSZbigniew Bodek #include <machine/bus.h>
532306b72aSZbigniew Bodek
542306b72aSZbigniew Bodek #include <dev/pci/pcireg.h>
552306b72aSZbigniew Bodek #include <dev/pci/pcivar.h>
562306b72aSZbigniew Bodek
572306b72aSZbigniew Bodek #include "thunder_bgx.h"
582306b72aSZbigniew Bodek #include "thunder_bgx_var.h"
593c0086b8SZbigniew Bodek #include "nic_reg.h"
603c0086b8SZbigniew Bodek #include "nic.h"
612306b72aSZbigniew Bodek
622306b72aSZbigniew Bodek #include "lmac_if.h"
632306b72aSZbigniew Bodek
642306b72aSZbigniew Bodek #define THUNDER_BGX_DEVSTR "ThunderX BGX Ethernet I/O Interface"
652306b72aSZbigniew Bodek
66be624ad4SZbigniew Bodek MALLOC_DEFINE(M_BGX, "thunder_bgx", "ThunderX BGX dynamic memory");
672306b72aSZbigniew Bodek
682306b72aSZbigniew Bodek #define BGX_NODE_ID_MASK 0x1
692306b72aSZbigniew Bodek #define BGX_NODE_ID_SHIFT 24
703c0086b8SZbigniew Bodek
713c0086b8SZbigniew Bodek #define DRV_NAME "thunder-BGX"
723c0086b8SZbigniew Bodek #define DRV_VERSION "1.0"
733c0086b8SZbigniew Bodek
742306b72aSZbigniew Bodek static int bgx_init_phy(struct bgx *);
753c0086b8SZbigniew Bodek
763c0086b8SZbigniew Bodek static struct bgx *bgx_vnic[MAX_BGX_THUNDER];
772306b72aSZbigniew Bodek static int lmac_count __unused; /* Total no of LMACs in system */
783c0086b8SZbigniew Bodek
793c0086b8SZbigniew Bodek static int bgx_xaui_check_link(struct lmac *lmac);
802306b72aSZbigniew Bodek static void bgx_get_qlm_mode(struct bgx *);
812306b72aSZbigniew Bodek static void bgx_init_hw(struct bgx *);
822306b72aSZbigniew Bodek static int bgx_lmac_enable(struct bgx *, uint8_t);
832306b72aSZbigniew Bodek static void bgx_lmac_disable(struct bgx *, uint8_t);
843c0086b8SZbigniew Bodek
852306b72aSZbigniew Bodek static int thunder_bgx_probe(device_t);
862306b72aSZbigniew Bodek static int thunder_bgx_attach(device_t);
872306b72aSZbigniew Bodek static int thunder_bgx_detach(device_t);
882306b72aSZbigniew Bodek
892306b72aSZbigniew Bodek static device_method_t thunder_bgx_methods[] = {
902306b72aSZbigniew Bodek /* Device interface */
912306b72aSZbigniew Bodek DEVMETHOD(device_probe, thunder_bgx_probe),
922306b72aSZbigniew Bodek DEVMETHOD(device_attach, thunder_bgx_attach),
932306b72aSZbigniew Bodek DEVMETHOD(device_detach, thunder_bgx_detach),
942306b72aSZbigniew Bodek
952306b72aSZbigniew Bodek DEVMETHOD_END,
963c0086b8SZbigniew Bodek };
973c0086b8SZbigniew Bodek
982306b72aSZbigniew Bodek static driver_t thunder_bgx_driver = {
992306b72aSZbigniew Bodek "bgx",
1002306b72aSZbigniew Bodek thunder_bgx_methods,
1012306b72aSZbigniew Bodek sizeof(struct lmac),
1022306b72aSZbigniew Bodek };
1033c0086b8SZbigniew Bodek
104*94412ad7SJohn Baldwin DRIVER_MODULE(thunder_bgx, pci, thunder_bgx_driver, 0, 0);
105f4aafb9eSWojciech Macek MODULE_VERSION(thunder_bgx, 1);
1062306b72aSZbigniew Bodek MODULE_DEPEND(thunder_bgx, pci, 1, 1, 1);
1072306b72aSZbigniew Bodek MODULE_DEPEND(thunder_bgx, ether, 1, 1, 1);
108f4aafb9eSWojciech Macek MODULE_DEPEND(thunder_bgx, thunder_mdio, 1, 1, 1);
1092306b72aSZbigniew Bodek
1102306b72aSZbigniew Bodek static int
thunder_bgx_probe(device_t dev)1112306b72aSZbigniew Bodek thunder_bgx_probe(device_t dev)
1122306b72aSZbigniew Bodek {
1132306b72aSZbigniew Bodek uint16_t vendor_id;
1142306b72aSZbigniew Bodek uint16_t device_id;
1152306b72aSZbigniew Bodek
1162306b72aSZbigniew Bodek vendor_id = pci_get_vendor(dev);
1172306b72aSZbigniew Bodek device_id = pci_get_device(dev);
1182306b72aSZbigniew Bodek
1192306b72aSZbigniew Bodek if (vendor_id == PCI_VENDOR_ID_CAVIUM &&
1202306b72aSZbigniew Bodek device_id == PCI_DEVICE_ID_THUNDER_BGX) {
1212306b72aSZbigniew Bodek device_set_desc(dev, THUNDER_BGX_DEVSTR);
1222306b72aSZbigniew Bodek return (BUS_PROBE_DEFAULT);
1232306b72aSZbigniew Bodek }
1242306b72aSZbigniew Bodek
1252306b72aSZbigniew Bodek return (ENXIO);
1262306b72aSZbigniew Bodek }
1272306b72aSZbigniew Bodek
1282306b72aSZbigniew Bodek static int
thunder_bgx_attach(device_t dev)1292306b72aSZbigniew Bodek thunder_bgx_attach(device_t dev)
1302306b72aSZbigniew Bodek {
1312306b72aSZbigniew Bodek struct bgx *bgx;
1327056927eSWojciech Macek uint8_t lmacid;
1332306b72aSZbigniew Bodek int err;
1342306b72aSZbigniew Bodek int rid;
1357056927eSWojciech Macek struct lmac *lmac;
1362306b72aSZbigniew Bodek
1372306b72aSZbigniew Bodek bgx = malloc(sizeof(*bgx), M_BGX, (M_WAITOK | M_ZERO));
1382306b72aSZbigniew Bodek bgx->dev = dev;
1397056927eSWojciech Macek
1407056927eSWojciech Macek lmac = device_get_softc(dev);
1417056927eSWojciech Macek lmac->bgx = bgx;
1422306b72aSZbigniew Bodek /* Enable bus mastering */
1432306b72aSZbigniew Bodek pci_enable_busmaster(dev);
1442306b72aSZbigniew Bodek /* Allocate resources - configuration registers */
1452306b72aSZbigniew Bodek rid = PCIR_BAR(PCI_CFG_REG_BAR_NUM);
1462306b72aSZbigniew Bodek bgx->reg_base = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1472306b72aSZbigniew Bodek RF_ACTIVE);
1482306b72aSZbigniew Bodek if (bgx->reg_base == NULL) {
1492306b72aSZbigniew Bodek device_printf(dev, "Could not allocate CSR memory space\n");
1502306b72aSZbigniew Bodek err = ENXIO;
1512306b72aSZbigniew Bodek goto err_disable_device;
1522306b72aSZbigniew Bodek }
1532306b72aSZbigniew Bodek
1542306b72aSZbigniew Bodek bgx->bgx_id = (rman_get_start(bgx->reg_base) >> BGX_NODE_ID_SHIFT) &
1552306b72aSZbigniew Bodek BGX_NODE_ID_MASK;
1562306b72aSZbigniew Bodek bgx->bgx_id += nic_get_node_id(bgx->reg_base) * MAX_BGX_PER_CN88XX;
1572306b72aSZbigniew Bodek
1582306b72aSZbigniew Bodek bgx_vnic[bgx->bgx_id] = bgx;
1592306b72aSZbigniew Bodek bgx_get_qlm_mode(bgx);
1602306b72aSZbigniew Bodek
1612306b72aSZbigniew Bodek err = bgx_init_phy(bgx);
1622306b72aSZbigniew Bodek if (err != 0)
1632306b72aSZbigniew Bodek goto err_free_res;
1642306b72aSZbigniew Bodek
1652306b72aSZbigniew Bodek bgx_init_hw(bgx);
1662306b72aSZbigniew Bodek
1672306b72aSZbigniew Bodek /* Enable all LMACs */
1687056927eSWojciech Macek for (lmacid = 0; lmacid < bgx->lmac_count; lmacid++) {
1697056927eSWojciech Macek err = bgx_lmac_enable(bgx, lmacid);
1702306b72aSZbigniew Bodek if (err) {
1712306b72aSZbigniew Bodek device_printf(dev, "BGX%d failed to enable lmac%d\n",
1727056927eSWojciech Macek bgx->bgx_id, lmacid);
1732306b72aSZbigniew Bodek goto err_free_res;
1742306b72aSZbigniew Bodek }
1752306b72aSZbigniew Bodek }
1762306b72aSZbigniew Bodek
1772306b72aSZbigniew Bodek return (0);
1782306b72aSZbigniew Bodek
1792306b72aSZbigniew Bodek err_free_res:
1802306b72aSZbigniew Bodek bgx_vnic[bgx->bgx_id] = NULL;
1812306b72aSZbigniew Bodek bus_release_resource(dev, SYS_RES_MEMORY,
1822306b72aSZbigniew Bodek rman_get_rid(bgx->reg_base), bgx->reg_base);
1832306b72aSZbigniew Bodek err_disable_device:
1842306b72aSZbigniew Bodek free(bgx, M_BGX);
1852306b72aSZbigniew Bodek pci_disable_busmaster(dev);
1862306b72aSZbigniew Bodek
1872306b72aSZbigniew Bodek return (err);
1882306b72aSZbigniew Bodek }
1892306b72aSZbigniew Bodek
1902306b72aSZbigniew Bodek static int
thunder_bgx_detach(device_t dev)1912306b72aSZbigniew Bodek thunder_bgx_detach(device_t dev)
1922306b72aSZbigniew Bodek {
1932306b72aSZbigniew Bodek struct lmac *lmac;
1942306b72aSZbigniew Bodek struct bgx *bgx;
1952306b72aSZbigniew Bodek uint8_t lmacid;
1962306b72aSZbigniew Bodek
1972306b72aSZbigniew Bodek lmac = device_get_softc(dev);
1982306b72aSZbigniew Bodek bgx = lmac->bgx;
1992306b72aSZbigniew Bodek /* Disable all LMACs */
2002306b72aSZbigniew Bodek for (lmacid = 0; lmacid < bgx->lmac_count; lmacid++)
2012306b72aSZbigniew Bodek bgx_lmac_disable(bgx, lmacid);
2022306b72aSZbigniew Bodek
2037056927eSWojciech Macek bgx_vnic[bgx->bgx_id] = NULL;
2047056927eSWojciech Macek bus_release_resource(dev, SYS_RES_MEMORY,
2057056927eSWojciech Macek rman_get_rid(bgx->reg_base), bgx->reg_base);
2067056927eSWojciech Macek free(bgx, M_BGX);
2077056927eSWojciech Macek pci_disable_busmaster(dev);
2087056927eSWojciech Macek
2092306b72aSZbigniew Bodek return (0);
2102306b72aSZbigniew Bodek }
2113c0086b8SZbigniew Bodek
2123c0086b8SZbigniew Bodek /* Register read/write APIs */
2132306b72aSZbigniew Bodek static uint64_t
bgx_reg_read(struct bgx * bgx,uint8_t lmac,uint64_t offset)2142306b72aSZbigniew Bodek bgx_reg_read(struct bgx *bgx, uint8_t lmac, uint64_t offset)
2153c0086b8SZbigniew Bodek {
2162306b72aSZbigniew Bodek bus_space_handle_t addr;
2173c0086b8SZbigniew Bodek
2182306b72aSZbigniew Bodek addr = ((uint32_t)lmac << 20) + offset;
2192306b72aSZbigniew Bodek
2202306b72aSZbigniew Bodek return (bus_read_8(bgx->reg_base, addr));
2213c0086b8SZbigniew Bodek }
2223c0086b8SZbigniew Bodek
2232306b72aSZbigniew Bodek static void
bgx_reg_write(struct bgx * bgx,uint8_t lmac,uint64_t offset,uint64_t val)2242306b72aSZbigniew Bodek bgx_reg_write(struct bgx *bgx, uint8_t lmac, uint64_t offset, uint64_t val)
2253c0086b8SZbigniew Bodek {
2262306b72aSZbigniew Bodek bus_space_handle_t addr;
2273c0086b8SZbigniew Bodek
2282306b72aSZbigniew Bodek addr = ((uint32_t)lmac << 20) + offset;
2292306b72aSZbigniew Bodek
2302306b72aSZbigniew Bodek bus_write_8(bgx->reg_base, addr, val);
2313c0086b8SZbigniew Bodek }
2323c0086b8SZbigniew Bodek
2332306b72aSZbigniew Bodek static void
bgx_reg_modify(struct bgx * bgx,uint8_t lmac,uint64_t offset,uint64_t val)2342306b72aSZbigniew Bodek bgx_reg_modify(struct bgx *bgx, uint8_t lmac, uint64_t offset, uint64_t val)
2353c0086b8SZbigniew Bodek {
2362306b72aSZbigniew Bodek bus_space_handle_t addr;
2373c0086b8SZbigniew Bodek
2382306b72aSZbigniew Bodek addr = ((uint32_t)lmac << 20) + offset;
2392306b72aSZbigniew Bodek
2402306b72aSZbigniew Bodek bus_write_8(bgx->reg_base, addr, val | bus_read_8(bgx->reg_base, addr));
2413c0086b8SZbigniew Bodek }
2423c0086b8SZbigniew Bodek
2432306b72aSZbigniew Bodek static int
bgx_poll_reg(struct bgx * bgx,uint8_t lmac,uint64_t reg,uint64_t mask,boolean_t zero)2442306b72aSZbigniew Bodek bgx_poll_reg(struct bgx *bgx, uint8_t lmac, uint64_t reg, uint64_t mask,
2452306b72aSZbigniew Bodek boolean_t zero)
2463c0086b8SZbigniew Bodek {
247d416a655SWojciech Macek int timeout = 10;
2482306b72aSZbigniew Bodek uint64_t reg_val;
2493c0086b8SZbigniew Bodek
2503c0086b8SZbigniew Bodek while (timeout) {
2513c0086b8SZbigniew Bodek reg_val = bgx_reg_read(bgx, lmac, reg);
2523c0086b8SZbigniew Bodek if (zero && !(reg_val & mask))
2532306b72aSZbigniew Bodek return (0);
2543c0086b8SZbigniew Bodek if (!zero && (reg_val & mask))
2552306b72aSZbigniew Bodek return (0);
2562306b72aSZbigniew Bodek
257d416a655SWojciech Macek DELAY(100);
2583c0086b8SZbigniew Bodek timeout--;
2593c0086b8SZbigniew Bodek }
2602306b72aSZbigniew Bodek return (ETIMEDOUT);
2613c0086b8SZbigniew Bodek }
2623c0086b8SZbigniew Bodek
2633c0086b8SZbigniew Bodek /* Return number of BGX present in HW */
2642306b72aSZbigniew Bodek u_int
bgx_get_map(int node)2652306b72aSZbigniew Bodek bgx_get_map(int node)
2663c0086b8SZbigniew Bodek {
2673c0086b8SZbigniew Bodek int i;
2682306b72aSZbigniew Bodek u_int map = 0;
2693c0086b8SZbigniew Bodek
2703c0086b8SZbigniew Bodek for (i = 0; i < MAX_BGX_PER_CN88XX; i++) {
2713c0086b8SZbigniew Bodek if (bgx_vnic[(node * MAX_BGX_PER_CN88XX) + i])
2723c0086b8SZbigniew Bodek map |= (1 << i);
2733c0086b8SZbigniew Bodek }
2743c0086b8SZbigniew Bodek
2752306b72aSZbigniew Bodek return (map);
2763c0086b8SZbigniew Bodek }
2773c0086b8SZbigniew Bodek
2783c0086b8SZbigniew Bodek /* Return number of LMAC configured for this BGX */
2792306b72aSZbigniew Bodek int
bgx_get_lmac_count(int node,int bgx_idx)2802306b72aSZbigniew Bodek bgx_get_lmac_count(int node, int bgx_idx)
2813c0086b8SZbigniew Bodek {
2823c0086b8SZbigniew Bodek struct bgx *bgx;
2833c0086b8SZbigniew Bodek
2843c0086b8SZbigniew Bodek bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
2852306b72aSZbigniew Bodek if (bgx != NULL)
2862306b72aSZbigniew Bodek return (bgx->lmac_count);
2873c0086b8SZbigniew Bodek
2882306b72aSZbigniew Bodek return (0);
2893c0086b8SZbigniew Bodek }
2903c0086b8SZbigniew Bodek
2913c0086b8SZbigniew Bodek /* Returns the current link status of LMAC */
2922306b72aSZbigniew Bodek void
bgx_get_lmac_link_state(int node,int bgx_idx,int lmacid,void * status)2932306b72aSZbigniew Bodek bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status)
2943c0086b8SZbigniew Bodek {
2953c0086b8SZbigniew Bodek struct bgx_link_status *link = (struct bgx_link_status *)status;
2963c0086b8SZbigniew Bodek struct bgx *bgx;
2973c0086b8SZbigniew Bodek struct lmac *lmac;
2983c0086b8SZbigniew Bodek
2993c0086b8SZbigniew Bodek bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
3002306b72aSZbigniew Bodek if (bgx == NULL)
3013c0086b8SZbigniew Bodek return;
3023c0086b8SZbigniew Bodek
3033c0086b8SZbigniew Bodek lmac = &bgx->lmac[lmacid];
3043c0086b8SZbigniew Bodek link->link_up = lmac->link_up;
3053c0086b8SZbigniew Bodek link->duplex = lmac->last_duplex;
3063c0086b8SZbigniew Bodek link->speed = lmac->last_speed;
3073c0086b8SZbigniew Bodek }
3083c0086b8SZbigniew Bodek
3092306b72aSZbigniew Bodek const uint8_t
bgx_get_lmac_mac(int node,int bgx_idx,int lmacid)3102306b72aSZbigniew Bodek *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid)
3113c0086b8SZbigniew Bodek {
3123c0086b8SZbigniew Bodek struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
3133c0086b8SZbigniew Bodek
3142306b72aSZbigniew Bodek if (bgx != NULL)
3152306b72aSZbigniew Bodek return (bgx->lmac[lmacid].mac);
3163c0086b8SZbigniew Bodek
3172306b72aSZbigniew Bodek return (NULL);
3183c0086b8SZbigniew Bodek }
3193c0086b8SZbigniew Bodek
3202306b72aSZbigniew Bodek void
bgx_set_lmac_mac(int node,int bgx_idx,int lmacid,const uint8_t * mac)3212306b72aSZbigniew Bodek bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const uint8_t *mac)
3223c0086b8SZbigniew Bodek {
3233c0086b8SZbigniew Bodek struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
3243c0086b8SZbigniew Bodek
3252306b72aSZbigniew Bodek if (bgx == NULL)
3263c0086b8SZbigniew Bodek return;
3273c0086b8SZbigniew Bodek
3282306b72aSZbigniew Bodek memcpy(bgx->lmac[lmacid].mac, mac, ETHER_ADDR_LEN);
3293c0086b8SZbigniew Bodek }
3303c0086b8SZbigniew Bodek
3312306b72aSZbigniew Bodek static void
bgx_sgmii_change_link_state(struct lmac * lmac)3322306b72aSZbigniew Bodek bgx_sgmii_change_link_state(struct lmac *lmac)
3333c0086b8SZbigniew Bodek {
3343c0086b8SZbigniew Bodek struct bgx *bgx = lmac->bgx;
3352306b72aSZbigniew Bodek uint64_t cmr_cfg;
3362306b72aSZbigniew Bodek uint64_t port_cfg = 0;
3372306b72aSZbigniew Bodek uint64_t misc_ctl = 0;
3383c0086b8SZbigniew Bodek
3393c0086b8SZbigniew Bodek cmr_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_CMRX_CFG);
3403c0086b8SZbigniew Bodek cmr_cfg &= ~CMR_EN;
3413c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid, BGX_CMRX_CFG, cmr_cfg);
3423c0086b8SZbigniew Bodek
3433c0086b8SZbigniew Bodek port_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG);
3443c0086b8SZbigniew Bodek misc_ctl = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_PCS_MISCX_CTL);
3453c0086b8SZbigniew Bodek
3463c0086b8SZbigniew Bodek if (lmac->link_up) {
3473c0086b8SZbigniew Bodek misc_ctl &= ~PCS_MISC_CTL_GMX_ENO;
3483c0086b8SZbigniew Bodek port_cfg &= ~GMI_PORT_CFG_DUPLEX;
3493c0086b8SZbigniew Bodek port_cfg |= (lmac->last_duplex << 2);
3503c0086b8SZbigniew Bodek } else {
3513c0086b8SZbigniew Bodek misc_ctl |= PCS_MISC_CTL_GMX_ENO;
3523c0086b8SZbigniew Bodek }
3533c0086b8SZbigniew Bodek
3543c0086b8SZbigniew Bodek switch (lmac->last_speed) {
3553c0086b8SZbigniew Bodek case 10:
3563c0086b8SZbigniew Bodek port_cfg &= ~GMI_PORT_CFG_SPEED; /* speed 0 */
3573c0086b8SZbigniew Bodek port_cfg |= GMI_PORT_CFG_SPEED_MSB; /* speed_msb 1 */
3583c0086b8SZbigniew Bodek port_cfg &= ~GMI_PORT_CFG_SLOT_TIME; /* slottime 0 */
3593c0086b8SZbigniew Bodek misc_ctl &= ~PCS_MISC_CTL_SAMP_PT_MASK;
3603c0086b8SZbigniew Bodek misc_ctl |= 50; /* samp_pt */
3613c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_SLOT, 64);
3623c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_BURST, 0);
3633c0086b8SZbigniew Bodek break;
3643c0086b8SZbigniew Bodek case 100:
3653c0086b8SZbigniew Bodek port_cfg &= ~GMI_PORT_CFG_SPEED; /* speed 0 */
3663c0086b8SZbigniew Bodek port_cfg &= ~GMI_PORT_CFG_SPEED_MSB; /* speed_msb 0 */
3673c0086b8SZbigniew Bodek port_cfg &= ~GMI_PORT_CFG_SLOT_TIME; /* slottime 0 */
3683c0086b8SZbigniew Bodek misc_ctl &= ~PCS_MISC_CTL_SAMP_PT_MASK;
3693c0086b8SZbigniew Bodek misc_ctl |= 5; /* samp_pt */
3703c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_SLOT, 64);
3713c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_BURST, 0);
3723c0086b8SZbigniew Bodek break;
3733c0086b8SZbigniew Bodek case 1000:
3743c0086b8SZbigniew Bodek port_cfg |= GMI_PORT_CFG_SPEED; /* speed 1 */
3753c0086b8SZbigniew Bodek port_cfg &= ~GMI_PORT_CFG_SPEED_MSB; /* speed_msb 0 */
3763c0086b8SZbigniew Bodek port_cfg |= GMI_PORT_CFG_SLOT_TIME; /* slottime 1 */
3773c0086b8SZbigniew Bodek misc_ctl &= ~PCS_MISC_CTL_SAMP_PT_MASK;
3783c0086b8SZbigniew Bodek misc_ctl |= 1; /* samp_pt */
3793c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_TXX_SLOT, 512);
3803c0086b8SZbigniew Bodek if (lmac->last_duplex)
3813c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid,
3823c0086b8SZbigniew Bodek BGX_GMP_GMI_TXX_BURST, 0);
3833c0086b8SZbigniew Bodek else
3843c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid,
3853c0086b8SZbigniew Bodek BGX_GMP_GMI_TXX_BURST, 8192);
3863c0086b8SZbigniew Bodek break;
3873c0086b8SZbigniew Bodek default:
3883c0086b8SZbigniew Bodek break;
3893c0086b8SZbigniew Bodek }
3903c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_PCS_MISCX_CTL, misc_ctl);
3913c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG, port_cfg);
3923c0086b8SZbigniew Bodek
3933c0086b8SZbigniew Bodek port_cfg = bgx_reg_read(bgx, lmac->lmacid, BGX_GMP_GMI_PRTX_CFG);
3943c0086b8SZbigniew Bodek
3953c0086b8SZbigniew Bodek /* renable lmac */
3963c0086b8SZbigniew Bodek cmr_cfg |= CMR_EN;
3973c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac->lmacid, BGX_CMRX_CFG, cmr_cfg);
3983c0086b8SZbigniew Bodek }
3993c0086b8SZbigniew Bodek
4002306b72aSZbigniew Bodek static void
bgx_lmac_handler(void * arg)4012306b72aSZbigniew Bodek bgx_lmac_handler(void *arg)
4023c0086b8SZbigniew Bodek {
4032306b72aSZbigniew Bodek struct lmac *lmac;
4042306b72aSZbigniew Bodek int link, duplex, speed;
4053c0086b8SZbigniew Bodek int link_changed = 0;
4062306b72aSZbigniew Bodek int err;
4073c0086b8SZbigniew Bodek
4082306b72aSZbigniew Bodek lmac = (struct lmac *)arg;
4093c0086b8SZbigniew Bodek
4102306b72aSZbigniew Bodek err = LMAC_MEDIA_STATUS(lmac->phy_if_dev, lmac->lmacid,
4112306b72aSZbigniew Bodek &link, &duplex, &speed);
4122306b72aSZbigniew Bodek if (err != 0)
4132306b72aSZbigniew Bodek goto out;
4142306b72aSZbigniew Bodek
4152306b72aSZbigniew Bodek if (!link && lmac->last_link)
4163c0086b8SZbigniew Bodek link_changed = -1;
4173c0086b8SZbigniew Bodek
4182306b72aSZbigniew Bodek if (link &&
4192306b72aSZbigniew Bodek (lmac->last_duplex != duplex ||
4202306b72aSZbigniew Bodek lmac->last_link != link ||
4212306b72aSZbigniew Bodek lmac->last_speed != speed)) {
4223c0086b8SZbigniew Bodek link_changed = 1;
4233c0086b8SZbigniew Bodek }
4243c0086b8SZbigniew Bodek
4252306b72aSZbigniew Bodek lmac->last_link = link;
4262306b72aSZbigniew Bodek lmac->last_speed = speed;
4272306b72aSZbigniew Bodek lmac->last_duplex = duplex;
4283c0086b8SZbigniew Bodek
4293c0086b8SZbigniew Bodek if (!link_changed)
4302306b72aSZbigniew Bodek goto out;
4313c0086b8SZbigniew Bodek
4323c0086b8SZbigniew Bodek if (link_changed > 0)
4333c0086b8SZbigniew Bodek lmac->link_up = true;
4343c0086b8SZbigniew Bodek else
4353c0086b8SZbigniew Bodek lmac->link_up = false;
4363c0086b8SZbigniew Bodek
4373c0086b8SZbigniew Bodek if (lmac->is_sgmii)
4383c0086b8SZbigniew Bodek bgx_sgmii_change_link_state(lmac);
4393c0086b8SZbigniew Bodek else
4403c0086b8SZbigniew Bodek bgx_xaui_check_link(lmac);
4412306b72aSZbigniew Bodek
4422306b72aSZbigniew Bodek out:
4432306b72aSZbigniew Bodek callout_reset(&lmac->check_link, hz * 2, bgx_lmac_handler, lmac);
4443c0086b8SZbigniew Bodek }
4453c0086b8SZbigniew Bodek
4462306b72aSZbigniew Bodek uint64_t
bgx_get_rx_stats(int node,int bgx_idx,int lmac,int idx)4472306b72aSZbigniew Bodek bgx_get_rx_stats(int node, int bgx_idx, int lmac, int idx)
4483c0086b8SZbigniew Bodek {
4493c0086b8SZbigniew Bodek struct bgx *bgx;
4503c0086b8SZbigniew Bodek
4513c0086b8SZbigniew Bodek bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
4522306b72aSZbigniew Bodek if (bgx == NULL)
4532306b72aSZbigniew Bodek return (0);
4543c0086b8SZbigniew Bodek
4553c0086b8SZbigniew Bodek if (idx > 8)
4562306b72aSZbigniew Bodek lmac = (0);
4572306b72aSZbigniew Bodek return (bgx_reg_read(bgx, lmac, BGX_CMRX_RX_STAT0 + (idx * 8)));
4583c0086b8SZbigniew Bodek }
4593c0086b8SZbigniew Bodek
4602306b72aSZbigniew Bodek uint64_t
bgx_get_tx_stats(int node,int bgx_idx,int lmac,int idx)4612306b72aSZbigniew Bodek bgx_get_tx_stats(int node, int bgx_idx, int lmac, int idx)
4623c0086b8SZbigniew Bodek {
4633c0086b8SZbigniew Bodek struct bgx *bgx;
4643c0086b8SZbigniew Bodek
4653c0086b8SZbigniew Bodek bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
4662306b72aSZbigniew Bodek if (bgx == NULL)
4672306b72aSZbigniew Bodek return (0);
4683c0086b8SZbigniew Bodek
4692306b72aSZbigniew Bodek return (bgx_reg_read(bgx, lmac, BGX_CMRX_TX_STAT0 + (idx * 8)));
4703c0086b8SZbigniew Bodek }
4713c0086b8SZbigniew Bodek
4722306b72aSZbigniew Bodek static void
bgx_flush_dmac_addrs(struct bgx * bgx,int lmac)4732306b72aSZbigniew Bodek bgx_flush_dmac_addrs(struct bgx *bgx, int lmac)
4743c0086b8SZbigniew Bodek {
4752306b72aSZbigniew Bodek uint64_t offset;
4763c0086b8SZbigniew Bodek
4773c0086b8SZbigniew Bodek while (bgx->lmac[lmac].dmac > 0) {
4782306b72aSZbigniew Bodek offset = ((bgx->lmac[lmac].dmac - 1) * sizeof(uint64_t)) +
4792306b72aSZbigniew Bodek (lmac * MAX_DMAC_PER_LMAC * sizeof(uint64_t));
4803c0086b8SZbigniew Bodek bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM + offset, 0);
4813c0086b8SZbigniew Bodek bgx->lmac[lmac].dmac--;
4823c0086b8SZbigniew Bodek }
4833c0086b8SZbigniew Bodek }
4843c0086b8SZbigniew Bodek
4852306b72aSZbigniew Bodek void
bgx_add_dmac_addr(uint64_t dmac,int node,int bgx_idx,int lmac)4862306b72aSZbigniew Bodek bgx_add_dmac_addr(uint64_t dmac, int node, int bgx_idx, int lmac)
4873c0086b8SZbigniew Bodek {
4882306b72aSZbigniew Bodek uint64_t offset;
4893c0086b8SZbigniew Bodek struct bgx *bgx;
4903c0086b8SZbigniew Bodek
4913c0086b8SZbigniew Bodek #ifdef BGX_IN_PROMISCUOUS_MODE
4923c0086b8SZbigniew Bodek return;
4933c0086b8SZbigniew Bodek #endif
4943c0086b8SZbigniew Bodek
4953c0086b8SZbigniew Bodek bgx_idx += node * MAX_BGX_PER_CN88XX;
4963c0086b8SZbigniew Bodek bgx = bgx_vnic[bgx_idx];
4973c0086b8SZbigniew Bodek
4983485f457SEd Maste if (bgx == NULL) {
4993485f457SEd Maste printf("BGX%d not yet initialized, ignoring DMAC addition\n",
5003c0086b8SZbigniew Bodek bgx_idx);
5013c0086b8SZbigniew Bodek return;
5023c0086b8SZbigniew Bodek }
5033c0086b8SZbigniew Bodek
5042306b72aSZbigniew Bodek dmac = dmac | (1UL << 48) | ((uint64_t)lmac << 49); /* Enable DMAC */
5053c0086b8SZbigniew Bodek if (bgx->lmac[lmac].dmac == MAX_DMAC_PER_LMAC) {
5062306b72aSZbigniew Bodek device_printf(bgx->dev,
5073c0086b8SZbigniew Bodek "Max DMAC filters for LMAC%d reached, ignoring\n",
5083c0086b8SZbigniew Bodek lmac);
5093c0086b8SZbigniew Bodek return;
5103c0086b8SZbigniew Bodek }
5113c0086b8SZbigniew Bodek
5123c0086b8SZbigniew Bodek if (bgx->lmac[lmac].dmac == MAX_DMAC_PER_LMAC_TNS_BYPASS_MODE)
5133c0086b8SZbigniew Bodek bgx->lmac[lmac].dmac = 1;
5143c0086b8SZbigniew Bodek
5152306b72aSZbigniew Bodek offset = (bgx->lmac[lmac].dmac * sizeof(uint64_t)) +
5162306b72aSZbigniew Bodek (lmac * MAX_DMAC_PER_LMAC * sizeof(uint64_t));
5173c0086b8SZbigniew Bodek bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM + offset, dmac);
5183c0086b8SZbigniew Bodek bgx->lmac[lmac].dmac++;
5193c0086b8SZbigniew Bodek
5203c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac, BGX_CMRX_RX_DMAC_CTL,
5212306b72aSZbigniew Bodek (CAM_ACCEPT << 3) | (MCAST_MODE_CAM_FILTER << 1) |
5222306b72aSZbigniew Bodek (BCAST_ACCEPT << 0));
5233c0086b8SZbigniew Bodek }
5243c0086b8SZbigniew Bodek
5253c0086b8SZbigniew Bodek /* Configure BGX LMAC in internal loopback mode */
5262306b72aSZbigniew Bodek void
bgx_lmac_internal_loopback(int node,int bgx_idx,int lmac_idx,boolean_t enable)5272306b72aSZbigniew Bodek bgx_lmac_internal_loopback(int node, int bgx_idx,
5282306b72aSZbigniew Bodek int lmac_idx, boolean_t enable)
5293c0086b8SZbigniew Bodek {
5303c0086b8SZbigniew Bodek struct bgx *bgx;
5313c0086b8SZbigniew Bodek struct lmac *lmac;
5322306b72aSZbigniew Bodek uint64_t cfg;
5333c0086b8SZbigniew Bodek
5343c0086b8SZbigniew Bodek bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
5352306b72aSZbigniew Bodek if (bgx == NULL)
5363c0086b8SZbigniew Bodek return;
5373c0086b8SZbigniew Bodek
5383c0086b8SZbigniew Bodek lmac = &bgx->lmac[lmac_idx];
5393c0086b8SZbigniew Bodek if (lmac->is_sgmii) {
5403c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL);
5413c0086b8SZbigniew Bodek if (enable)
5423c0086b8SZbigniew Bodek cfg |= PCS_MRX_CTL_LOOPBACK1;
5433c0086b8SZbigniew Bodek else
5443c0086b8SZbigniew Bodek cfg &= ~PCS_MRX_CTL_LOOPBACK1;
5453c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL, cfg);
5463c0086b8SZbigniew Bodek } else {
5473c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmac_idx, BGX_SPUX_CONTROL1);
5483c0086b8SZbigniew Bodek if (enable)
5493c0086b8SZbigniew Bodek cfg |= SPU_CTL_LOOPBACK;
5503c0086b8SZbigniew Bodek else
5513c0086b8SZbigniew Bodek cfg &= ~SPU_CTL_LOOPBACK;
5523c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmac_idx, BGX_SPUX_CONTROL1, cfg);
5533c0086b8SZbigniew Bodek }
5543c0086b8SZbigniew Bodek }
5553c0086b8SZbigniew Bodek
5562306b72aSZbigniew Bodek static int
bgx_lmac_sgmii_init(struct bgx * bgx,int lmacid)5572306b72aSZbigniew Bodek bgx_lmac_sgmii_init(struct bgx *bgx, int lmacid)
5583c0086b8SZbigniew Bodek {
5592306b72aSZbigniew Bodek uint64_t cfg;
5603c0086b8SZbigniew Bodek
5613c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_THRESH, 0x30);
5623c0086b8SZbigniew Bodek /* max packet size */
5633c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_RXX_JABBER, MAX_FRAME_SIZE);
5643c0086b8SZbigniew Bodek
5653c0086b8SZbigniew Bodek /* Disable frame alignment if using preamble */
5663c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND);
5673c0086b8SZbigniew Bodek if (cfg & 1)
5683c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_SGMII_CTL, 0);
5693c0086b8SZbigniew Bodek
5703c0086b8SZbigniew Bodek /* Enable lmac */
5713c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
5723c0086b8SZbigniew Bodek
5733c0086b8SZbigniew Bodek /* PCS reset */
5743c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, PCS_MRX_CTL_RESET);
5753c0086b8SZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_CTL,
5762306b72aSZbigniew Bodek PCS_MRX_CTL_RESET, TRUE) != 0) {
5772306b72aSZbigniew Bodek device_printf(bgx->dev, "BGX PCS reset not completed\n");
5782306b72aSZbigniew Bodek return (ENXIO);
5793c0086b8SZbigniew Bodek }
5803c0086b8SZbigniew Bodek
5813c0086b8SZbigniew Bodek /* power down, reset autoneg, autoneg enable */
5823c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL);
5833c0086b8SZbigniew Bodek cfg &= ~PCS_MRX_CTL_PWR_DN;
5843c0086b8SZbigniew Bodek cfg |= (PCS_MRX_CTL_RST_AN | PCS_MRX_CTL_AN_EN);
5853c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg);
5863c0086b8SZbigniew Bodek
5873c0086b8SZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS,
5882306b72aSZbigniew Bodek PCS_MRX_STATUS_AN_CPT, FALSE) != 0) {
5892306b72aSZbigniew Bodek device_printf(bgx->dev, "BGX AN_CPT not completed\n");
5902306b72aSZbigniew Bodek return (ENXIO);
5913c0086b8SZbigniew Bodek }
5923c0086b8SZbigniew Bodek
5932306b72aSZbigniew Bodek return (0);
5943c0086b8SZbigniew Bodek }
5953c0086b8SZbigniew Bodek
5962306b72aSZbigniew Bodek static int
bgx_lmac_xaui_init(struct bgx * bgx,int lmacid,int lmac_type)5972306b72aSZbigniew Bodek bgx_lmac_xaui_init(struct bgx *bgx, int lmacid, int lmac_type)
5983c0086b8SZbigniew Bodek {
5992306b72aSZbigniew Bodek uint64_t cfg;
6003c0086b8SZbigniew Bodek
6013c0086b8SZbigniew Bodek /* Reset SPU */
6023c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_RESET);
6032306b72aSZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_CONTROL1,
6042306b72aSZbigniew Bodek SPU_CTL_RESET, TRUE) != 0) {
6052306b72aSZbigniew Bodek device_printf(bgx->dev, "BGX SPU reset not completed\n");
6062306b72aSZbigniew Bodek return (ENXIO);
6073c0086b8SZbigniew Bodek }
6083c0086b8SZbigniew Bodek
6093c0086b8SZbigniew Bodek /* Disable LMAC */
6103c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
6113c0086b8SZbigniew Bodek cfg &= ~CMR_EN;
6123c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
6133c0086b8SZbigniew Bodek
6143c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SPUX_CONTROL1, SPU_CTL_LOW_POWER);
6153c0086b8SZbigniew Bodek /* Set interleaved running disparity for RXAUI */
6162306b72aSZbigniew Bodek if (bgx->lmac_type != BGX_MODE_RXAUI) {
6173c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid,
6183c0086b8SZbigniew Bodek BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
6192306b72aSZbigniew Bodek } else {
6203c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL,
6213c0086b8SZbigniew Bodek SPU_MISC_CTL_RX_DIS | SPU_MISC_CTL_INTLV_RDISP);
6222306b72aSZbigniew Bodek }
6233c0086b8SZbigniew Bodek
6243c0086b8SZbigniew Bodek /* clear all interrupts */
6253c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_RX_INT);
6263c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SMUX_RX_INT, cfg);
6273c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_INT);
6283c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_INT, cfg);
6293c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
6303c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
6313c0086b8SZbigniew Bodek
6323c0086b8SZbigniew Bodek if (bgx->use_training) {
6333c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LP_CUP, 0x00);
6343c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LD_CUP, 0x00);
6353c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_LD_REP, 0x00);
6363c0086b8SZbigniew Bodek /* training enable */
6372306b72aSZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL,
6382306b72aSZbigniew Bodek SPU_PMD_CRTL_TRAIN_EN);
6393c0086b8SZbigniew Bodek }
6403c0086b8SZbigniew Bodek
6413c0086b8SZbigniew Bodek /* Append FCS to each packet */
6423c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_APPEND, SMU_TX_APPEND_FCS_D);
6433c0086b8SZbigniew Bodek
6443c0086b8SZbigniew Bodek /* Disable forward error correction */
6453c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_FEC_CONTROL);
6463c0086b8SZbigniew Bodek cfg &= ~SPU_FEC_CTL_FEC_EN;
6473c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_FEC_CONTROL, cfg);
6483c0086b8SZbigniew Bodek
6493c0086b8SZbigniew Bodek /* Disable autoneg */
6503c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_CONTROL);
6513c0086b8SZbigniew Bodek cfg = cfg & ~(SPU_AN_CTL_AN_EN | SPU_AN_CTL_XNP_EN);
6523c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_AN_CONTROL, cfg);
6533c0086b8SZbigniew Bodek
6543c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_AN_ADV);
6553c0086b8SZbigniew Bodek if (bgx->lmac_type == BGX_MODE_10G_KR)
6563c0086b8SZbigniew Bodek cfg |= (1 << 23);
6573c0086b8SZbigniew Bodek else if (bgx->lmac_type == BGX_MODE_40G_KR)
6583c0086b8SZbigniew Bodek cfg |= (1 << 24);
6593c0086b8SZbigniew Bodek else
6603c0086b8SZbigniew Bodek cfg &= ~((1 << 23) | (1 << 24));
6612306b72aSZbigniew Bodek cfg = cfg & (~((1UL << 25) | (1UL << 22) | (1UL << 12)));
6623c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_AN_ADV, cfg);
6633c0086b8SZbigniew Bodek
6643c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, 0, BGX_SPU_DBG_CONTROL);
6653c0086b8SZbigniew Bodek cfg &= ~SPU_DBG_CTL_AN_ARB_LINK_CHK_EN;
6663c0086b8SZbigniew Bodek bgx_reg_write(bgx, 0, BGX_SPU_DBG_CONTROL, cfg);
6673c0086b8SZbigniew Bodek
6683c0086b8SZbigniew Bodek /* Enable lmac */
6693c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
6703c0086b8SZbigniew Bodek
6713c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_CONTROL1);
6723c0086b8SZbigniew Bodek cfg &= ~SPU_CTL_LOW_POWER;
6733c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_CONTROL1, cfg);
6743c0086b8SZbigniew Bodek
6753c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_CTL);
6763c0086b8SZbigniew Bodek cfg &= ~SMU_TX_CTL_UNI_EN;
6773c0086b8SZbigniew Bodek cfg |= SMU_TX_CTL_DIC_EN;
6783c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_CTL, cfg);
6793c0086b8SZbigniew Bodek
6803c0086b8SZbigniew Bodek /* take lmac_count into account */
6813c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_THRESH, (0x100 - 1));
6823c0086b8SZbigniew Bodek /* max packet size */
6833c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SMUX_RX_JABBER, MAX_FRAME_SIZE);
6843c0086b8SZbigniew Bodek
6852306b72aSZbigniew Bodek return (0);
6863c0086b8SZbigniew Bodek }
6873c0086b8SZbigniew Bodek
6882306b72aSZbigniew Bodek static int
bgx_xaui_check_link(struct lmac * lmac)6892306b72aSZbigniew Bodek bgx_xaui_check_link(struct lmac *lmac)
6903c0086b8SZbigniew Bodek {
6913c0086b8SZbigniew Bodek struct bgx *bgx = lmac->bgx;
6923c0086b8SZbigniew Bodek int lmacid = lmac->lmacid;
6933c0086b8SZbigniew Bodek int lmac_type = bgx->lmac_type;
6942306b72aSZbigniew Bodek uint64_t cfg;
6953c0086b8SZbigniew Bodek
6963c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SPUX_MISC_CONTROL, SPU_MISC_CTL_RX_DIS);
6973c0086b8SZbigniew Bodek if (bgx->use_training) {
6983c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
6992306b72aSZbigniew Bodek if ((cfg & (1UL << 13)) == 0) {
7002306b72aSZbigniew Bodek cfg = (1UL << 13) | (1UL << 14);
7013c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
7023c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL);
7032306b72aSZbigniew Bodek cfg |= (1UL << 0);
7043c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_BR_PMD_CRTL, cfg);
7052306b72aSZbigniew Bodek return (ENXIO);
7063c0086b8SZbigniew Bodek }
7073c0086b8SZbigniew Bodek }
7083c0086b8SZbigniew Bodek
7093c0086b8SZbigniew Bodek /* wait for PCS to come out of reset */
7102306b72aSZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_CONTROL1,
7112306b72aSZbigniew Bodek SPU_CTL_RESET, TRUE) != 0) {
7122306b72aSZbigniew Bodek device_printf(bgx->dev, "BGX SPU reset not completed\n");
7132306b72aSZbigniew Bodek return (ENXIO);
7143c0086b8SZbigniew Bodek }
7153c0086b8SZbigniew Bodek
7163c0086b8SZbigniew Bodek if ((lmac_type == BGX_MODE_10G_KR) || (lmac_type == BGX_MODE_XFI) ||
7173c0086b8SZbigniew Bodek (lmac_type == BGX_MODE_40G_KR) || (lmac_type == BGX_MODE_XLAUI)) {
7183c0086b8SZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_BR_STATUS1,
7192306b72aSZbigniew Bodek SPU_BR_STATUS_BLK_LOCK, FALSE)) {
7202306b72aSZbigniew Bodek device_printf(bgx->dev,
7213c0086b8SZbigniew Bodek "SPU_BR_STATUS_BLK_LOCK not completed\n");
7222306b72aSZbigniew Bodek return (ENXIO);
7233c0086b8SZbigniew Bodek }
7243c0086b8SZbigniew Bodek } else {
7253c0086b8SZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_BX_STATUS,
7262306b72aSZbigniew Bodek SPU_BX_STATUS_RX_ALIGN, FALSE) != 0) {
7272306b72aSZbigniew Bodek device_printf(bgx->dev,
7283c0086b8SZbigniew Bodek "SPU_BX_STATUS_RX_ALIGN not completed\n");
7292306b72aSZbigniew Bodek return (ENXIO);
7303c0086b8SZbigniew Bodek }
7313c0086b8SZbigniew Bodek }
7323c0086b8SZbigniew Bodek
7333c0086b8SZbigniew Bodek /* Clear rcvflt bit (latching high) and read it back */
7343c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS2, SPU_STATUS2_RCVFLT);
7353c0086b8SZbigniew Bodek if (bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) & SPU_STATUS2_RCVFLT) {
7362306b72aSZbigniew Bodek device_printf(bgx->dev, "Receive fault, retry training\n");
7373c0086b8SZbigniew Bodek if (bgx->use_training) {
7383c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_INT);
7392306b72aSZbigniew Bodek if ((cfg & (1UL << 13)) == 0) {
7402306b72aSZbigniew Bodek cfg = (1UL << 13) | (1UL << 14);
7413c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_INT, cfg);
7423c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid,
7433c0086b8SZbigniew Bodek BGX_SPUX_BR_PMD_CRTL);
7442306b72aSZbigniew Bodek cfg |= (1UL << 0);
7453c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid,
7463c0086b8SZbigniew Bodek BGX_SPUX_BR_PMD_CRTL, cfg);
7472306b72aSZbigniew Bodek return (ENXIO);
7483c0086b8SZbigniew Bodek }
7493c0086b8SZbigniew Bodek }
7502306b72aSZbigniew Bodek return (ENXIO);
7513c0086b8SZbigniew Bodek }
7523c0086b8SZbigniew Bodek
7533c0086b8SZbigniew Bodek /* Wait for MAC RX to be ready */
7543c0086b8SZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_RX_CTL,
7552306b72aSZbigniew Bodek SMU_RX_CTL_STATUS, TRUE) != 0) {
7562306b72aSZbigniew Bodek device_printf(bgx->dev, "SMU RX link not okay\n");
7572306b72aSZbigniew Bodek return (ENXIO);
7583c0086b8SZbigniew Bodek }
7593c0086b8SZbigniew Bodek
7603c0086b8SZbigniew Bodek /* Wait for BGX RX to be idle */
7612306b72aSZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL,
7622306b72aSZbigniew Bodek SMU_CTL_RX_IDLE, FALSE) != 0) {
7632306b72aSZbigniew Bodek device_printf(bgx->dev, "SMU RX not idle\n");
7642306b72aSZbigniew Bodek return (ENXIO);
7653c0086b8SZbigniew Bodek }
7663c0086b8SZbigniew Bodek
7673c0086b8SZbigniew Bodek /* Wait for BGX TX to be idle */
7682306b72aSZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_SMUX_CTL,
7692306b72aSZbigniew Bodek SMU_CTL_TX_IDLE, FALSE) != 0) {
7702306b72aSZbigniew Bodek device_printf(bgx->dev, "SMU TX not idle\n");
7712306b72aSZbigniew Bodek return (ENXIO);
7723c0086b8SZbigniew Bodek }
7733c0086b8SZbigniew Bodek
7742306b72aSZbigniew Bodek if ((bgx_reg_read(bgx, lmacid, BGX_SPUX_STATUS2) &
7752306b72aSZbigniew Bodek SPU_STATUS2_RCVFLT) != 0) {
7762306b72aSZbigniew Bodek device_printf(bgx->dev, "Receive fault\n");
7772306b72aSZbigniew Bodek return (ENXIO);
7783c0086b8SZbigniew Bodek }
7793c0086b8SZbigniew Bodek
7803c0086b8SZbigniew Bodek /* Receive link is latching low. Force it high and verify it */
7813c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SPUX_STATUS1, SPU_STATUS1_RCV_LNK);
7823c0086b8SZbigniew Bodek if (bgx_poll_reg(bgx, lmacid, BGX_SPUX_STATUS1,
7832306b72aSZbigniew Bodek SPU_STATUS1_RCV_LNK, FALSE) != 0) {
7842306b72aSZbigniew Bodek device_printf(bgx->dev, "SPU receive link down\n");
7852306b72aSZbigniew Bodek return (ENXIO);
7863c0086b8SZbigniew Bodek }
7873c0086b8SZbigniew Bodek
7883c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SPUX_MISC_CONTROL);
7893c0086b8SZbigniew Bodek cfg &= ~SPU_MISC_CTL_RX_DIS;
7903c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SPUX_MISC_CONTROL, cfg);
7912306b72aSZbigniew Bodek return (0);
7923c0086b8SZbigniew Bodek }
7933c0086b8SZbigniew Bodek
7942306b72aSZbigniew Bodek static void
bgx_poll_for_link(void * arg)7952306b72aSZbigniew Bodek bgx_poll_for_link(void *arg)
7963c0086b8SZbigniew Bodek {
7973c0086b8SZbigniew Bodek struct lmac *lmac;
7982306b72aSZbigniew Bodek uint64_t link;
7993c0086b8SZbigniew Bodek
8002306b72aSZbigniew Bodek lmac = (struct lmac *)arg;
8013c0086b8SZbigniew Bodek
8023c0086b8SZbigniew Bodek /* Receive link is latching low. Force it high and verify it */
8033c0086b8SZbigniew Bodek bgx_reg_modify(lmac->bgx, lmac->lmacid,
8043c0086b8SZbigniew Bodek BGX_SPUX_STATUS1, SPU_STATUS1_RCV_LNK);
8053c0086b8SZbigniew Bodek bgx_poll_reg(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1,
8063c0086b8SZbigniew Bodek SPU_STATUS1_RCV_LNK, false);
8073c0086b8SZbigniew Bodek
8083c0086b8SZbigniew Bodek link = bgx_reg_read(lmac->bgx, lmac->lmacid, BGX_SPUX_STATUS1);
8093c0086b8SZbigniew Bodek if (link & SPU_STATUS1_RCV_LNK) {
8103c0086b8SZbigniew Bodek lmac->link_up = 1;
8113c0086b8SZbigniew Bodek if (lmac->bgx->lmac_type == BGX_MODE_XLAUI)
8123c0086b8SZbigniew Bodek lmac->last_speed = 40000;
8133c0086b8SZbigniew Bodek else
8143c0086b8SZbigniew Bodek lmac->last_speed = 10000;
8153c0086b8SZbigniew Bodek lmac->last_duplex = 1;
8163c0086b8SZbigniew Bodek } else {
8173c0086b8SZbigniew Bodek lmac->link_up = 0;
8183c0086b8SZbigniew Bodek }
8193c0086b8SZbigniew Bodek
8203c0086b8SZbigniew Bodek if (lmac->last_link != lmac->link_up) {
8213c0086b8SZbigniew Bodek lmac->last_link = lmac->link_up;
8223c0086b8SZbigniew Bodek if (lmac->link_up)
8233c0086b8SZbigniew Bodek bgx_xaui_check_link(lmac);
8243c0086b8SZbigniew Bodek }
8253c0086b8SZbigniew Bodek
8262306b72aSZbigniew Bodek callout_reset(&lmac->check_link, hz * 2, bgx_poll_for_link, lmac);
8273c0086b8SZbigniew Bodek }
8283c0086b8SZbigniew Bodek
8292306b72aSZbigniew Bodek static int
bgx_lmac_enable(struct bgx * bgx,uint8_t lmacid)8302306b72aSZbigniew Bodek bgx_lmac_enable(struct bgx *bgx, uint8_t lmacid)
8313c0086b8SZbigniew Bodek {
8322306b72aSZbigniew Bodek uint64_t __unused dmac_bcast = (1UL << 48) - 1;
8333c0086b8SZbigniew Bodek struct lmac *lmac;
8342306b72aSZbigniew Bodek uint64_t cfg;
8353c0086b8SZbigniew Bodek
8363c0086b8SZbigniew Bodek lmac = &bgx->lmac[lmacid];
8373c0086b8SZbigniew Bodek lmac->bgx = bgx;
8383c0086b8SZbigniew Bodek
8393c0086b8SZbigniew Bodek if (bgx->lmac_type == BGX_MODE_SGMII) {
8403c0086b8SZbigniew Bodek lmac->is_sgmii = 1;
8412306b72aSZbigniew Bodek if (bgx_lmac_sgmii_init(bgx, lmacid) != 0)
8423c0086b8SZbigniew Bodek return -1;
8433c0086b8SZbigniew Bodek } else {
8443c0086b8SZbigniew Bodek lmac->is_sgmii = 0;
8453c0086b8SZbigniew Bodek if (bgx_lmac_xaui_init(bgx, lmacid, bgx->lmac_type))
8463c0086b8SZbigniew Bodek return -1;
8473c0086b8SZbigniew Bodek }
8483c0086b8SZbigniew Bodek
8493c0086b8SZbigniew Bodek if (lmac->is_sgmii) {
8503c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND);
8512306b72aSZbigniew Bodek cfg |= ((1UL << 2) | (1UL << 1)); /* FCS and PAD */
8523c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_GMP_GMI_TXX_APPEND, cfg);
8533c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_GMP_GMI_TXX_MIN_PKT, 60 - 1);
8543c0086b8SZbigniew Bodek } else {
8553c0086b8SZbigniew Bodek cfg = bgx_reg_read(bgx, lmacid, BGX_SMUX_TX_APPEND);
8562306b72aSZbigniew Bodek cfg |= ((1UL << 2) | (1UL << 1)); /* FCS and PAD */
8573c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_SMUX_TX_APPEND, cfg);
8583c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_SMUX_TX_MIN_PKT, 60 + 4);
8593c0086b8SZbigniew Bodek }
8603c0086b8SZbigniew Bodek
8613c0086b8SZbigniew Bodek /* Enable lmac */
8623c0086b8SZbigniew Bodek bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG,
8633c0086b8SZbigniew Bodek CMR_EN | CMR_PKT_RX_EN | CMR_PKT_TX_EN);
8643c0086b8SZbigniew Bodek
8653c0086b8SZbigniew Bodek /* Restore default cfg, incase low level firmware changed it */
8663c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_CMRX_RX_DMAC_CTL, 0x03);
8673c0086b8SZbigniew Bodek
8683c0086b8SZbigniew Bodek /* Add broadcast MAC into all LMAC's DMAC filters */
8693c0086b8SZbigniew Bodek bgx_add_dmac_addr(dmac_bcast, 0, bgx->bgx_id, lmacid);
8703c0086b8SZbigniew Bodek
8713c0086b8SZbigniew Bodek if ((bgx->lmac_type != BGX_MODE_XFI) &&
8722306b72aSZbigniew Bodek (bgx->lmac_type != BGX_MODE_XAUI) &&
8733c0086b8SZbigniew Bodek (bgx->lmac_type != BGX_MODE_XLAUI) &&
8743c0086b8SZbigniew Bodek (bgx->lmac_type != BGX_MODE_40G_KR) &&
8753c0086b8SZbigniew Bodek (bgx->lmac_type != BGX_MODE_10G_KR)) {
8762306b72aSZbigniew Bodek if (lmac->phy_if_dev == NULL) {
8772306b72aSZbigniew Bodek device_printf(bgx->dev,
8782306b72aSZbigniew Bodek "LMAC%d missing interface to PHY\n", lmacid);
8792306b72aSZbigniew Bodek return (ENXIO);
8802306b72aSZbigniew Bodek }
8813c0086b8SZbigniew Bodek
8822306b72aSZbigniew Bodek if (LMAC_PHY_CONNECT(lmac->phy_if_dev, lmac->phyaddr,
8832306b72aSZbigniew Bodek lmacid) != 0) {
8842306b72aSZbigniew Bodek device_printf(bgx->dev,
8852306b72aSZbigniew Bodek "LMAC%d could not connect to PHY\n", lmacid);
8862306b72aSZbigniew Bodek return (ENXIO);
8872306b72aSZbigniew Bodek }
8882306b72aSZbigniew Bodek mtx_init(&lmac->check_link_mtx, "BGX link poll", NULL, MTX_DEF);
8892306b72aSZbigniew Bodek callout_init_mtx(&lmac->check_link, &lmac->check_link_mtx, 0);
8902306b72aSZbigniew Bodek mtx_lock(&lmac->check_link_mtx);
8912306b72aSZbigniew Bodek bgx_lmac_handler(lmac);
8922306b72aSZbigniew Bodek mtx_unlock(&lmac->check_link_mtx);
8933c0086b8SZbigniew Bodek } else {
8942306b72aSZbigniew Bodek mtx_init(&lmac->check_link_mtx, "BGX link poll", NULL, MTX_DEF);
8952306b72aSZbigniew Bodek callout_init_mtx(&lmac->check_link, &lmac->check_link_mtx, 0);
8962306b72aSZbigniew Bodek mtx_lock(&lmac->check_link_mtx);
8972306b72aSZbigniew Bodek bgx_poll_for_link(lmac);
8982306b72aSZbigniew Bodek mtx_unlock(&lmac->check_link_mtx);
8993c0086b8SZbigniew Bodek }
9003c0086b8SZbigniew Bodek
9012306b72aSZbigniew Bodek return (0);
9023c0086b8SZbigniew Bodek }
9033c0086b8SZbigniew Bodek
9042306b72aSZbigniew Bodek static void
bgx_lmac_disable(struct bgx * bgx,uint8_t lmacid)9052306b72aSZbigniew Bodek bgx_lmac_disable(struct bgx *bgx, uint8_t lmacid)
9063c0086b8SZbigniew Bodek {
9073c0086b8SZbigniew Bodek struct lmac *lmac;
9082306b72aSZbigniew Bodek uint64_t cmrx_cfg;
9093c0086b8SZbigniew Bodek
9103c0086b8SZbigniew Bodek lmac = &bgx->lmac[lmacid];
9112306b72aSZbigniew Bodek
9122306b72aSZbigniew Bodek /* Stop callout */
9132306b72aSZbigniew Bodek callout_drain(&lmac->check_link);
9142306b72aSZbigniew Bodek mtx_destroy(&lmac->check_link_mtx);
9153c0086b8SZbigniew Bodek
9163c0086b8SZbigniew Bodek cmrx_cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
9173c0086b8SZbigniew Bodek cmrx_cfg &= ~(1 << 15);
9183c0086b8SZbigniew Bodek bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cmrx_cfg);
9193c0086b8SZbigniew Bodek bgx_flush_dmac_addrs(bgx, lmacid);
9203c0086b8SZbigniew Bodek
9213c0086b8SZbigniew Bodek if ((bgx->lmac_type != BGX_MODE_XFI) &&
9223c0086b8SZbigniew Bodek (bgx->lmac_type != BGX_MODE_XLAUI) &&
9233c0086b8SZbigniew Bodek (bgx->lmac_type != BGX_MODE_40G_KR) &&
9243c0086b8SZbigniew Bodek (bgx->lmac_type != BGX_MODE_10G_KR)) {
9252306b72aSZbigniew Bodek if (lmac->phy_if_dev == NULL) {
9262306b72aSZbigniew Bodek device_printf(bgx->dev,
9272306b72aSZbigniew Bodek "LMAC%d missing interface to PHY\n", lmacid);
9282306b72aSZbigniew Bodek return;
9293c0086b8SZbigniew Bodek }
9302306b72aSZbigniew Bodek if (LMAC_PHY_DISCONNECT(lmac->phy_if_dev, lmac->phyaddr,
9312306b72aSZbigniew Bodek lmacid) != 0) {
9322306b72aSZbigniew Bodek device_printf(bgx->dev,
9332306b72aSZbigniew Bodek "LMAC%d could not disconnect PHY\n", lmacid);
9342306b72aSZbigniew Bodek return;
9352306b72aSZbigniew Bodek }
9362306b72aSZbigniew Bodek lmac->phy_if_dev = NULL;
9372306b72aSZbigniew Bodek }
9383c0086b8SZbigniew Bodek }
9393c0086b8SZbigniew Bodek
9402306b72aSZbigniew Bodek static void
bgx_set_num_ports(struct bgx * bgx)9412306b72aSZbigniew Bodek bgx_set_num_ports(struct bgx *bgx)
9423c0086b8SZbigniew Bodek {
9432306b72aSZbigniew Bodek uint64_t lmac_count;
9443c0086b8SZbigniew Bodek
9453c0086b8SZbigniew Bodek switch (bgx->qlm_mode) {
9463c0086b8SZbigniew Bodek case QLM_MODE_SGMII:
9473c0086b8SZbigniew Bodek bgx->lmac_count = 4;
9483c0086b8SZbigniew Bodek bgx->lmac_type = BGX_MODE_SGMII;
9493c0086b8SZbigniew Bodek bgx->lane_to_sds = 0;
9503c0086b8SZbigniew Bodek break;
9513c0086b8SZbigniew Bodek case QLM_MODE_XAUI_1X4:
9523c0086b8SZbigniew Bodek bgx->lmac_count = 1;
9533c0086b8SZbigniew Bodek bgx->lmac_type = BGX_MODE_XAUI;
9543c0086b8SZbigniew Bodek bgx->lane_to_sds = 0xE4;
9553c0086b8SZbigniew Bodek break;
9563c0086b8SZbigniew Bodek case QLM_MODE_RXAUI_2X2:
9573c0086b8SZbigniew Bodek bgx->lmac_count = 2;
9583c0086b8SZbigniew Bodek bgx->lmac_type = BGX_MODE_RXAUI;
9593c0086b8SZbigniew Bodek bgx->lane_to_sds = 0xE4;
9603c0086b8SZbigniew Bodek break;
9613c0086b8SZbigniew Bodek case QLM_MODE_XFI_4X1:
9623c0086b8SZbigniew Bodek bgx->lmac_count = 4;
9633c0086b8SZbigniew Bodek bgx->lmac_type = BGX_MODE_XFI;
9643c0086b8SZbigniew Bodek bgx->lane_to_sds = 0;
9653c0086b8SZbigniew Bodek break;
9663c0086b8SZbigniew Bodek case QLM_MODE_XLAUI_1X4:
9673c0086b8SZbigniew Bodek bgx->lmac_count = 1;
9683c0086b8SZbigniew Bodek bgx->lmac_type = BGX_MODE_XLAUI;
9693c0086b8SZbigniew Bodek bgx->lane_to_sds = 0xE4;
9703c0086b8SZbigniew Bodek break;
9713c0086b8SZbigniew Bodek case QLM_MODE_10G_KR_4X1:
9723c0086b8SZbigniew Bodek bgx->lmac_count = 4;
9733c0086b8SZbigniew Bodek bgx->lmac_type = BGX_MODE_10G_KR;
9743c0086b8SZbigniew Bodek bgx->lane_to_sds = 0;
9753c0086b8SZbigniew Bodek bgx->use_training = 1;
9763c0086b8SZbigniew Bodek break;
9773c0086b8SZbigniew Bodek case QLM_MODE_40G_KR4_1X4:
9783c0086b8SZbigniew Bodek bgx->lmac_count = 1;
9793c0086b8SZbigniew Bodek bgx->lmac_type = BGX_MODE_40G_KR;
9803c0086b8SZbigniew Bodek bgx->lane_to_sds = 0xE4;
9813c0086b8SZbigniew Bodek bgx->use_training = 1;
9823c0086b8SZbigniew Bodek break;
9833c0086b8SZbigniew Bodek default:
9843c0086b8SZbigniew Bodek bgx->lmac_count = 0;
9853c0086b8SZbigniew Bodek break;
9863c0086b8SZbigniew Bodek }
9873c0086b8SZbigniew Bodek
9882306b72aSZbigniew Bodek /*
9892306b72aSZbigniew Bodek * Check if low level firmware has programmed LMAC count
9903c0086b8SZbigniew Bodek * based on board type, if yes consider that otherwise
9913c0086b8SZbigniew Bodek * the default static values
9923c0086b8SZbigniew Bodek */
9933c0086b8SZbigniew Bodek lmac_count = bgx_reg_read(bgx, 0, BGX_CMR_RX_LMACS) & 0x7;
9943c0086b8SZbigniew Bodek if (lmac_count != 4)
9953c0086b8SZbigniew Bodek bgx->lmac_count = lmac_count;
9963c0086b8SZbigniew Bodek }
9973c0086b8SZbigniew Bodek
9982306b72aSZbigniew Bodek static void
bgx_init_hw(struct bgx * bgx)9992306b72aSZbigniew Bodek bgx_init_hw(struct bgx *bgx)
10003c0086b8SZbigniew Bodek {
10013c0086b8SZbigniew Bodek int i;
10023c0086b8SZbigniew Bodek
10033c0086b8SZbigniew Bodek bgx_set_num_ports(bgx);
10043c0086b8SZbigniew Bodek
10053c0086b8SZbigniew Bodek bgx_reg_modify(bgx, 0, BGX_CMR_GLOBAL_CFG, CMR_GLOBAL_CFG_FCS_STRIP);
10063c0086b8SZbigniew Bodek if (bgx_reg_read(bgx, 0, BGX_CMR_BIST_STATUS))
10072306b72aSZbigniew Bodek device_printf(bgx->dev, "BGX%d BIST failed\n", bgx->bgx_id);
10083c0086b8SZbigniew Bodek
10093c0086b8SZbigniew Bodek /* Set lmac type and lane2serdes mapping */
10103c0086b8SZbigniew Bodek for (i = 0; i < bgx->lmac_count; i++) {
10113c0086b8SZbigniew Bodek if (bgx->lmac_type == BGX_MODE_RXAUI) {
10123c0086b8SZbigniew Bodek if (i)
10133c0086b8SZbigniew Bodek bgx->lane_to_sds = 0x0e;
10143c0086b8SZbigniew Bodek else
10153c0086b8SZbigniew Bodek bgx->lane_to_sds = 0x04;
10163c0086b8SZbigniew Bodek bgx_reg_write(bgx, i, BGX_CMRX_CFG,
10173c0086b8SZbigniew Bodek (bgx->lmac_type << 8) | bgx->lane_to_sds);
10183c0086b8SZbigniew Bodek continue;
10193c0086b8SZbigniew Bodek }
10203c0086b8SZbigniew Bodek bgx_reg_write(bgx, i, BGX_CMRX_CFG,
10213c0086b8SZbigniew Bodek (bgx->lmac_type << 8) | (bgx->lane_to_sds + i));
10223c0086b8SZbigniew Bodek bgx->lmac[i].lmacid_bd = lmac_count;
10233c0086b8SZbigniew Bodek lmac_count++;
10243c0086b8SZbigniew Bodek }
10253c0086b8SZbigniew Bodek
10263c0086b8SZbigniew Bodek bgx_reg_write(bgx, 0, BGX_CMR_TX_LMACS, bgx->lmac_count);
10273c0086b8SZbigniew Bodek bgx_reg_write(bgx, 0, BGX_CMR_RX_LMACS, bgx->lmac_count);
10283c0086b8SZbigniew Bodek
10293c0086b8SZbigniew Bodek /* Set the backpressure AND mask */
10302306b72aSZbigniew Bodek for (i = 0; i < bgx->lmac_count; i++) {
10313c0086b8SZbigniew Bodek bgx_reg_modify(bgx, 0, BGX_CMR_CHAN_MSK_AND,
10322306b72aSZbigniew Bodek ((1UL << MAX_BGX_CHANS_PER_LMAC) - 1) <<
10333c0086b8SZbigniew Bodek (i * MAX_BGX_CHANS_PER_LMAC));
10342306b72aSZbigniew Bodek }
10353c0086b8SZbigniew Bodek
10363c0086b8SZbigniew Bodek /* Disable all MAC filtering */
10373c0086b8SZbigniew Bodek for (i = 0; i < RX_DMAC_COUNT; i++)
10383c0086b8SZbigniew Bodek bgx_reg_write(bgx, 0, BGX_CMR_RX_DMACX_CAM + (i * 8), 0x00);
10393c0086b8SZbigniew Bodek
10403c0086b8SZbigniew Bodek /* Disable MAC steering (NCSI traffic) */
10413c0086b8SZbigniew Bodek for (i = 0; i < RX_TRAFFIC_STEER_RULE_COUNT; i++)
10423c0086b8SZbigniew Bodek bgx_reg_write(bgx, 0, BGX_CMR_RX_STREERING + (i * 8), 0x00);
10433c0086b8SZbigniew Bodek }
10443c0086b8SZbigniew Bodek
10452306b72aSZbigniew Bodek static void
bgx_get_qlm_mode(struct bgx * bgx)10462306b72aSZbigniew Bodek bgx_get_qlm_mode(struct bgx *bgx)
10473c0086b8SZbigniew Bodek {
1048aeb665b5SEd Maste device_t dev = bgx->dev;
10493c0086b8SZbigniew Bodek int lmac_type;
10503c0086b8SZbigniew Bodek int train_en;
10513c0086b8SZbigniew Bodek
10523c0086b8SZbigniew Bodek /* Read LMAC0 type to figure out QLM mode
10533c0086b8SZbigniew Bodek * This is configured by low level firmware
10543c0086b8SZbigniew Bodek */
10553c0086b8SZbigniew Bodek lmac_type = bgx_reg_read(bgx, 0, BGX_CMRX_CFG);
10563c0086b8SZbigniew Bodek lmac_type = (lmac_type >> 8) & 0x07;
10573c0086b8SZbigniew Bodek
10583c0086b8SZbigniew Bodek train_en = bgx_reg_read(bgx, 0, BGX_SPUX_BR_PMD_CRTL) &
10593c0086b8SZbigniew Bodek SPU_PMD_CRTL_TRAIN_EN;
10603c0086b8SZbigniew Bodek
10613c0086b8SZbigniew Bodek switch (lmac_type) {
10623c0086b8SZbigniew Bodek case BGX_MODE_SGMII:
10633c0086b8SZbigniew Bodek bgx->qlm_mode = QLM_MODE_SGMII;
10642306b72aSZbigniew Bodek if (bootverbose) {
10652306b72aSZbigniew Bodek device_printf(dev, "BGX%d QLM mode: SGMII\n",
10662306b72aSZbigniew Bodek bgx->bgx_id);
10672306b72aSZbigniew Bodek }
10683c0086b8SZbigniew Bodek break;
10693c0086b8SZbigniew Bodek case BGX_MODE_XAUI:
10703c0086b8SZbigniew Bodek bgx->qlm_mode = QLM_MODE_XAUI_1X4;
10712306b72aSZbigniew Bodek if (bootverbose) {
10722306b72aSZbigniew Bodek device_printf(dev, "BGX%d QLM mode: XAUI\n",
10732306b72aSZbigniew Bodek bgx->bgx_id);
10742306b72aSZbigniew Bodek }
10753c0086b8SZbigniew Bodek break;
10763c0086b8SZbigniew Bodek case BGX_MODE_RXAUI:
10773c0086b8SZbigniew Bodek bgx->qlm_mode = QLM_MODE_RXAUI_2X2;
10782306b72aSZbigniew Bodek if (bootverbose) {
10792306b72aSZbigniew Bodek device_printf(dev, "BGX%d QLM mode: RXAUI\n",
10802306b72aSZbigniew Bodek bgx->bgx_id);
10812306b72aSZbigniew Bodek }
10823c0086b8SZbigniew Bodek break;
10833c0086b8SZbigniew Bodek case BGX_MODE_XFI:
10843c0086b8SZbigniew Bodek if (!train_en) {
10853c0086b8SZbigniew Bodek bgx->qlm_mode = QLM_MODE_XFI_4X1;
10862306b72aSZbigniew Bodek if (bootverbose) {
10872306b72aSZbigniew Bodek device_printf(dev, "BGX%d QLM mode: XFI\n",
10882306b72aSZbigniew Bodek bgx->bgx_id);
10892306b72aSZbigniew Bodek }
10903c0086b8SZbigniew Bodek } else {
10913c0086b8SZbigniew Bodek bgx->qlm_mode = QLM_MODE_10G_KR_4X1;
10922306b72aSZbigniew Bodek if (bootverbose) {
10932306b72aSZbigniew Bodek device_printf(dev, "BGX%d QLM mode: 10G_KR\n",
10942306b72aSZbigniew Bodek bgx->bgx_id);
10952306b72aSZbigniew Bodek }
10963c0086b8SZbigniew Bodek }
10973c0086b8SZbigniew Bodek break;
10983c0086b8SZbigniew Bodek case BGX_MODE_XLAUI:
10993c0086b8SZbigniew Bodek if (!train_en) {
11003c0086b8SZbigniew Bodek bgx->qlm_mode = QLM_MODE_XLAUI_1X4;
11012306b72aSZbigniew Bodek if (bootverbose) {
11022306b72aSZbigniew Bodek device_printf(dev, "BGX%d QLM mode: XLAUI\n",
11032306b72aSZbigniew Bodek bgx->bgx_id);
11042306b72aSZbigniew Bodek }
11053c0086b8SZbigniew Bodek } else {
11063c0086b8SZbigniew Bodek bgx->qlm_mode = QLM_MODE_40G_KR4_1X4;
11072306b72aSZbigniew Bodek if (bootverbose) {
11082306b72aSZbigniew Bodek device_printf(dev, "BGX%d QLM mode: 40G_KR4\n",
11092306b72aSZbigniew Bodek bgx->bgx_id);
11102306b72aSZbigniew Bodek }
11113c0086b8SZbigniew Bodek }
11123c0086b8SZbigniew Bodek break;
11133c0086b8SZbigniew Bodek default:
11143c0086b8SZbigniew Bodek bgx->qlm_mode = QLM_MODE_SGMII;
11152306b72aSZbigniew Bodek if (bootverbose) {
11162306b72aSZbigniew Bodek device_printf(dev, "BGX%d QLM default mode: SGMII\n",
11172306b72aSZbigniew Bodek bgx->bgx_id);
11182306b72aSZbigniew Bodek }
11193c0086b8SZbigniew Bodek }
11203c0086b8SZbigniew Bodek }
11213c0086b8SZbigniew Bodek
11222306b72aSZbigniew Bodek static int
bgx_init_phy(struct bgx * bgx)11232306b72aSZbigniew Bodek bgx_init_phy(struct bgx *bgx)
11243c0086b8SZbigniew Bodek {
11253c0086b8SZbigniew Bodek int err;
11263c0086b8SZbigniew Bodek
11272306b72aSZbigniew Bodek /* By default we fail */
11282306b72aSZbigniew Bodek err = ENXIO;
11292306b72aSZbigniew Bodek #ifdef FDT
11302306b72aSZbigniew Bodek err = bgx_fdt_init_phy(bgx);
11312306b72aSZbigniew Bodek #endif
11322306b72aSZbigniew Bodek #ifdef ACPI
11332306b72aSZbigniew Bodek if (err != 0) {
11342306b72aSZbigniew Bodek /* ARM64TODO: Add ACPI function here */
11353c0086b8SZbigniew Bodek }
11362306b72aSZbigniew Bodek #endif
11372306b72aSZbigniew Bodek return (err);
11383c0086b8SZbigniew Bodek }
1139