Date: Thu, 12 Nov 2009 21:27:58 +0000 (UTC) From: Oleksandr Tymoshenko <gonzo@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r199234 - projects/mips/sys/mips/atheros Message-ID: <200911122127.nACLRwg3043837@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: gonzo Date: Thu Nov 12 21:27:58 2009 New Revision: 199234 URL: http://svn.freebsd.org/changeset/base/199234 Log: - Handle multiphy MAC case: create interface with fixed-state media with parameters set via hints and configure MAC accordingly to these parameters. All the underlying PHY magic is done by boot manager on startup. At the moment there is no proper way to make active and control all PHYs simultaneously from one MII bus and there is no way to associate incoming/outgoing packet with specific PHY. Modified: projects/mips/sys/mips/atheros/if_arge.c projects/mips/sys/mips/atheros/if_argevar.h Modified: projects/mips/sys/mips/atheros/if_arge.c ============================================================================== --- projects/mips/sys/mips/atheros/if_arge.c Thu Nov 12 20:48:04 2009 (r199233) +++ projects/mips/sys/mips/atheros/if_arge.c Thu Nov 12 21:27:58 2009 (r199234) @@ -95,6 +95,7 @@ static int arge_ioctl(struct ifnet *, u_ static void arge_init(void *); static void arge_init_locked(struct arge_softc *); static void arge_link_task(void *, int); +static void arge_set_pll(struct arge_softc *, int, int); static int arge_miibus_readreg(device_t, int, int); static void arge_miibus_statchg(device_t); static int arge_miibus_writereg(device_t, int, int, int); @@ -118,6 +119,12 @@ static void arge_intr(void *); static int arge_intr_filter(void *); static void arge_tick(void *); +/* + * ifmedia callbacks for multiPHY MAC + */ +void arge_multiphy_mediastatus(struct ifnet *, struct ifmediareq *); +int arge_multiphy_mediachange(struct ifnet *); + static void arge_dmamap_cb(void *, bus_dma_segment_t *, int, int); static int arge_dma_alloc(struct arge_softc *); static void arge_dma_free(struct arge_softc *); @@ -197,9 +204,10 @@ arge_attach(device_t dev) uint8_t eaddr[ETHER_ADDR_LEN]; struct ifnet *ifp; struct arge_softc *sc; - int error = 0, rid, phynum; + int error = 0, rid, phymask; uint32_t reg, rnd; - int is_base_mac_empty, i; + int is_base_mac_empty, i, phys_total; + uint32_t hint; sc = device_get_softc(dev); sc->arge_dev = dev; @@ -221,20 +229,43 @@ arge_attach(device_t dev) * Get which PHY of 5 available we should use for this unit */ if (resource_int_value(device_get_name(dev), device_get_unit(dev), - "phy", &phynum) != 0) { + "phymask", &phymask) != 0) { /* * Use port 4 (WAN) for GE0. For any other port use * its PHY the same as its unit number */ if (sc->arge_mac_unit == 0) - phynum = 4; + phymask = (1 << 4); else - phynum = sc->arge_mac_unit; + /* Use all phys up to 4 */ + phymask = (1 << 4) - 1; - device_printf(dev, "No PHY specified, using %d\n", phynum); + device_printf(dev, "No PHY specified, using mask %d\n", phymask); } - sc->arge_phy_num = phynum; + /* + * Get default media & duplex mode, by default its Base100T + * and full duplex + */ + if (resource_int_value(device_get_name(dev), device_get_unit(dev), + "media", &hint) != 0) + hint = 0; + + if (hint == 1000) + sc->arge_media_type = IFM_1000_T; + else + sc->arge_media_type = IFM_100_TX; + + if (resource_int_value(device_get_name(dev), device_get_unit(dev), + "fduplex", &hint) != 0) + hint = 1; + + if (hint) + sc->arge_duplex_mode = IFM_FDX; + else + sc->arge_duplex_mode = 0; + + sc->arge_phymask = phymask; mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); @@ -379,14 +410,40 @@ arge_attach(device_t dev) ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, FIFO_RX_FILTMASK_DEFAULT); - /* Do MII setup. */ - if (mii_phy_probe(dev, &sc->arge_miibus, - arge_ifmedia_upd, arge_ifmedia_sts)) { - device_printf(dev, "MII without any phy!\n"); - error = ENXIO; + /* + * Check if we have single-PHY MAC or multi-PHY + */ + phys_total = 0; + for (i = 0; i < ARGE_NPHY; i++) + if (phymask & (1 << i)) + phys_total ++; + + if (phys_total == 0) { + error = EINVAL; goto fail; } + if (phys_total == 1) { + /* Do MII setup. */ + if (mii_phy_probe(dev, &sc->arge_miibus, + arge_ifmedia_upd, arge_ifmedia_sts)) { + device_printf(dev, "MII without any phy!\n"); + error = ENXIO; + goto fail; + } + } + else { + ifmedia_init(&sc->arge_ifmedia, 0, + arge_multiphy_mediachange, + arge_multiphy_mediastatus); + ifmedia_add(&sc->arge_ifmedia, + IFM_ETHER | sc->arge_media_type | sc->arge_duplex_mode, + 0, NULL); + ifmedia_set(&sc->arge_ifmedia, + IFM_ETHER | sc->arge_media_type | sc->arge_duplex_mode); + arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode); + } + /* Call MI attach routine. */ ether_ifattach(ifp, eaddr); @@ -432,6 +489,7 @@ arge_detach(device_t dev) if (sc->arge_miibus) device_delete_child(dev, sc->arge_miibus); + bus_generic_detach(dev); if (sc->arge_intrhand) @@ -490,7 +548,7 @@ arge_miibus_readreg(device_t dev, int ph uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK); - if (phy != sc->arge_phy_num) + if ((sc->arge_phymask & (1 << phy)) == 0) return (0); mtx_lock(&miibus_mtx); @@ -529,7 +587,7 @@ arge_miibus_writereg(device_t dev, int p (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK); - if (phy != sc->arge_phy_num) + if ((sc->arge_phymask & (1 << phy)) == 0) return (-1); dprintf("%s: phy=%d, reg=%02x, value=%04x\n", __func__, @@ -570,8 +628,7 @@ arge_link_task(void *arg, int pending) struct arge_softc *sc; struct mii_data *mii; struct ifnet *ifp; - uint32_t media; - uint32_t cfg, ifcontrol, rx_filtmask, pll, sec_cfg; + uint32_t media, duplex; sc = (struct arge_softc *)arg; @@ -590,68 +647,8 @@ arge_link_task(void *arg, int pending) if (media != IFM_NONE) { sc->arge_link_status = 1; - - cfg = ARGE_READ(sc, AR71XX_MAC_CFG2); - cfg &= ~(MAC_CFG2_IFACE_MODE_1000 - | MAC_CFG2_IFACE_MODE_10_100 - | MAC_CFG2_FULL_DUPLEX); - - if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) - cfg |= MAC_CFG2_FULL_DUPLEX; - - ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL); - ifcontrol &= ~MAC_IFCONTROL_SPEED; - rx_filtmask = - ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK); - rx_filtmask &= ~FIFO_RX_MASK_BYTE_MODE; - - switch(media) { - case IFM_10_T: - cfg |= MAC_CFG2_IFACE_MODE_10_100; - pll = PLL_ETH_INT_CLK_10; - break; - case IFM_100_TX: - cfg |= MAC_CFG2_IFACE_MODE_10_100; - ifcontrol |= MAC_IFCONTROL_SPEED; - pll = PLL_ETH_INT_CLK_100; - break; - case IFM_1000_T: - case IFM_1000_SX: - cfg |= MAC_CFG2_IFACE_MODE_1000; - rx_filtmask |= FIFO_RX_MASK_BYTE_MODE; - pll = PLL_ETH_INT_CLK_1000; - break; - default: - pll = PLL_ETH_INT_CLK_100; - device_printf(sc->arge_dev, - "Unknown media %d\n", media); - } - - ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD, - 0x008001ff); - - ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg); - ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol); - ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, - rx_filtmask); - - /* set PLL registers */ - sec_cfg = ATH_READ_REG(AR71XX_PLL_SEC_CONFIG); - sec_cfg &= ~(3 << sc->arge_pll_reg_shift); - sec_cfg |= (2 << sc->arge_pll_reg_shift); - - ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg); - DELAY(100); - - ATH_WRITE_REG(sc->arge_pll_reg, pll); - - sec_cfg |= (3 << sc->arge_pll_reg_shift); - ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg); - DELAY(100); - - sec_cfg &= ~(3 << sc->arge_pll_reg_shift); - ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg); - DELAY(100); + duplex = mii->mii_media_active & IFM_GMASK; + arge_set_pll(sc, media, duplex); } } else sc->arge_link_status = 0; @@ -660,6 +657,75 @@ arge_link_task(void *arg, int pending) } static void +arge_set_pll(struct arge_softc *sc, int media, int duplex) +{ + uint32_t cfg, ifcontrol, rx_filtmask, pll, sec_cfg; + + cfg = ARGE_READ(sc, AR71XX_MAC_CFG2); + cfg &= ~(MAC_CFG2_IFACE_MODE_1000 + | MAC_CFG2_IFACE_MODE_10_100 + | MAC_CFG2_FULL_DUPLEX); + + if (duplex == IFM_FDX) + cfg |= MAC_CFG2_FULL_DUPLEX; + + ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL); + ifcontrol &= ~MAC_IFCONTROL_SPEED; + rx_filtmask = + ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK); + rx_filtmask &= ~FIFO_RX_MASK_BYTE_MODE; + + switch(media) { + case IFM_10_T: + cfg |= MAC_CFG2_IFACE_MODE_10_100; + pll = PLL_ETH_INT_CLK_10; + break; + case IFM_100_TX: + cfg |= MAC_CFG2_IFACE_MODE_10_100; + ifcontrol |= MAC_IFCONTROL_SPEED; + pll = PLL_ETH_INT_CLK_100; + break; + case IFM_1000_T: + case IFM_1000_SX: + cfg |= MAC_CFG2_IFACE_MODE_1000; + rx_filtmask |= FIFO_RX_MASK_BYTE_MODE; + pll = PLL_ETH_INT_CLK_1000; + break; + default: + pll = PLL_ETH_INT_CLK_100; + device_printf(sc->arge_dev, + "Unknown media %d\n", media); + } + + ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD, + 0x008001ff); + + ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg); + ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol); + ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, + rx_filtmask); + + /* set PLL registers */ + sec_cfg = ATH_READ_REG(AR71XX_PLL_SEC_CONFIG); + sec_cfg &= ~(3 << sc->arge_pll_reg_shift); + sec_cfg |= (2 << sc->arge_pll_reg_shift); + + ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg); + DELAY(100); + + ATH_WRITE_REG(sc->arge_pll_reg, pll); + + sec_cfg |= (3 << sc->arge_pll_reg_shift); + ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg); + DELAY(100); + + sec_cfg &= ~(3 << sc->arge_pll_reg_shift); + ATH_WRITE_REG(AR71XX_PLL_SEC_CONFIG, sec_cfg); + DELAY(100); +} + + +static void arge_reset_dma(struct arge_softc *sc) { ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, 0); @@ -707,8 +773,6 @@ arge_init_locked(struct arge_softc *sc) ARGE_LOCK_ASSERT(sc); - mii = device_get_softc(sc->arge_miibus); - arge_stop(sc); /* Init circular RX list. */ @@ -724,13 +788,24 @@ arge_init_locked(struct arge_softc *sc) arge_reset_dma(sc); - sc->arge_link_status = 0; - mii_mediachg(mii); + + if (sc->arge_miibus) { + sc->arge_link_status = 0; + mii = device_get_softc(sc->arge_miibus); + mii_mediachg(mii); + } + else { + /* + * Sun always shines over multiPHY interface + */ + sc->arge_link_status = 1; + } ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); + if (sc->arge_miibus) + callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0)); ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0)); @@ -899,7 +974,8 @@ arge_stop(struct arge_softc *sc) ifp = sc->arge_ifp; ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); - callout_stop(&sc->arge_stat_callout); + if (sc->arge_miibus) + callout_stop(&sc->arge_stat_callout); /* mask out interrupts */ ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); @@ -948,8 +1024,12 @@ arge_ioctl(struct ifnet *ifp, u_long com break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: - mii = device_get_softc(sc->arge_miibus); - error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); + if (sc->arge_miibus) { + mii = device_get_softc(sc->arge_miibus); + error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); + } + else + error = ifmedia_ioctl(ifp, ifr, &sc->arge_ifmedia, command); break; case SIOCSIFCAP: /* XXX: Check other capabilities */ @@ -1690,7 +1770,42 @@ arge_tick(void *xsc) ARGE_LOCK_ASSERT(sc); - mii = device_get_softc(sc->arge_miibus); - mii_tick(mii); - callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); + if (sc->arge_miibus) { + mii = device_get_softc(sc->arge_miibus); + mii_tick(mii); + callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); + } } + +int +arge_multiphy_mediachange(struct ifnet *ifp) +{ + struct arge_softc *sc = ifp->if_softc; + struct ifmedia *ifm = &sc->arge_ifmedia; + struct ifmedia_entry *ife = ifm->ifm_cur; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + return (EINVAL); + + if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { + device_printf(sc->arge_dev, + "AUTO is not supported for multiphy MAC"); + return (EINVAL); + } + + /* + * Ignore everything + */ + return (0); +} + +void +arge_multiphy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct arge_softc *sc = ifp->if_softc; + + ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; + ifmr->ifm_active = IFM_ETHER | sc->arge_media_type | + sc->arge_duplex_mode; +} + Modified: projects/mips/sys/mips/atheros/if_argevar.h ============================================================================== --- projects/mips/sys/mips/atheros/if_argevar.h Thu Nov 12 20:48:04 2009 (r199233) +++ projects/mips/sys/mips/atheros/if_argevar.h Thu Nov 12 21:27:58 2009 (r199234) @@ -28,6 +28,7 @@ #ifndef __IF_ARGEVAR_H__ #define __IF_ARGEVAR_H__ +#define ARGE_NPHY 32 #define ARGE_TX_RING_COUNT 128 #define ARGE_RX_RING_COUNT 128 #define ARGE_RX_DMA_SIZE ARGE_RX_RING_COUNT * sizeof(struct arge_desc) @@ -124,6 +125,12 @@ struct arge_ring_data { struct arge_softc { struct ifnet *arge_ifp; /* interface info */ device_t arge_dev; + struct ifmedia arge_ifmedia; + /* + * Media & duples settings for multiPHY MAC + */ + uint32_t arge_media_type; + uint32_t arge_duplex_mode; struct resource *arge_res; int arge_rid; struct resource *arge_irq; @@ -140,7 +147,7 @@ struct arge_softc { int arge_detach; uint32_t arge_intr_status; int arge_mac_unit; - int arge_phy_num; + int arge_phymask; uint32_t arge_ddr_flush_reg; uint32_t arge_pll_reg; uint32_t arge_pll_reg_shift;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200911122127.nACLRwg3043837>