static int pm3393_disable(struct cmac *cmac, int which) { if (which & MAC_DIRECTION_RX) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, RXXG_CONF1_VAL); if (which & MAC_DIRECTION_TX) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, TXXG_CONF1_VAL); udelay(20); cmac->instance->enabled &= ~which; return 0; }
static int pm3393_disable(struct cmac *cmac, int which) { if (which & MAC_DIRECTION_RX) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, RXXG_CONF1_VAL); if (which & MAC_DIRECTION_TX) pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, TXXG_CONF1_VAL); /* * The disable is graceful. Give the PM3393 time. Can't wait very * long here, we may be holding locks. */ udelay(20); cmac->instance->enabled &= ~which; return 0; }
static int pm3393_set_mtu(struct cmac *cmac, int mtu) { int enabled = cmac->instance->enabled; mtu += ETH_HLEN + ETH_FCS_LEN; /* Disable Rx/Tx MAC before configuring it. */ if (enabled) pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu); pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu); if (enabled) pm3393_enable(cmac, enabled); return 0; }
static int pm3393_enable(struct cmac *cmac, int which) { if (which & MAC_DIRECTION_RX) pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_1, (RXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_RXXG_RXEN)); if (which & MAC_DIRECTION_TX) { u32 val = TXXG_CONF1_VAL | SUNI1x10GEXP_BITMSK_TXXG_TXEN0; if (cmac->instance->fc & PAUSE_RX) val |= SUNI1x10GEXP_BITMSK_TXXG_FCRX; if (cmac->instance->fc & PAUSE_TX) val |= SUNI1x10GEXP_BITMSK_TXXG_FCTX; pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_1, val); } cmac->instance->enabled |= which; return 0; }
static int pm3393_set_mtu(struct cmac *cmac, int mtu) { int enabled = cmac->instance->enabled; mtu += 14 + 4; if (mtu > MAX_FRAME_SIZE) return -EINVAL; if (enabled) pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu); pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu); if (enabled) pm3393_enable(cmac, enabled); return 0; }
static int pm3393_set_mtu(struct cmac *cmac, int mtu) { int enabled = cmac->instance->enabled; /* MAX_FRAME_SIZE includes header + FCS, mtu doesn't */ mtu += 14 + 4; if (mtu > MAX_FRAME_SIZE) return -EINVAL; /* Disable Rx/Tx MAC before configuring it. */ if (enabled) pm3393_disable(cmac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MAX_FRAME_LENGTH, mtu); pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_MAX_FRAME_SIZE, mtu); if (enabled) pm3393_enable(cmac, enabled); return 0; }
static int pm3393_enable_port(struct cmac *cmac, int which) { pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_CONTROL, SUNI1x10GEXP_BITMSK_MSTAT_CLEAR); udelay(2); memset(&cmac->stats, 0, sizeof(struct cmac_statistics)); pm3393_enable(cmac, which); t1_link_changed(cmac->adapter, 0); return 0; }
static int pm3393_set_rx_mode(struct cmac *cmac, struct t1_rx_mode *rm) { int enabled = cmac->instance->enabled & MAC_DIRECTION_RX; u32 rx_mode; /* Disable MAC RX before reconfiguring it */ if (enabled) pm3393_disable(cmac, MAC_DIRECTION_RX); pmread(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, &rx_mode); rx_mode &= ~(SUNI1x10GEXP_BITMSK_RXXG_PMODE | SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_ADDRESS_FILTER_CONTROL_2, (u16)rx_mode); if (t1_rx_mode_promisc(rm)) { /* Promiscuous mode. */ rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_PMODE; } if (t1_rx_mode_allmulti(rm)) { /* Accept all multicast. */ pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, 0xffff); rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN; } else if (t1_rx_mode_mc_cnt(rm)) { /* Accept one or more multicast(s). */ struct netdev_hw_addr *ha; int bit; u16 mc_filter[4] = { 0, }; netdev_for_each_mc_addr(ha, t1_get_netdev(rm)) { /* bit[23:28] */ bit = (ether_crc(ETH_ALEN, ha->addr) >> 23) & 0x3f; mc_filter[bit >> 4] |= 1 << (bit & 0xf); } pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_LOW, mc_filter[0]); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDLOW, mc_filter[1]); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_MIDHIGH, mc_filter[2]); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_MULTICAST_HASH_HIGH, mc_filter[3]); rx_mode |= SUNI1x10GEXP_BITMSK_RXXG_MHASH_EN; }
static int pm3393_enable_port(struct cmac *cmac, int which) { /* Clear port statistics */ pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_CONTROL, SUNI1x10GEXP_BITMSK_MSTAT_CLEAR); udelay(2); memset(&cmac->stats, 0, sizeof(struct cmac_statistics)); pm3393_enable(cmac, which); /* * XXX This should be done by the PHY and preferably not at all. * The PHY doesn't give us link status indication on its own so have * the link management code query it instead. */ t1_link_changed(cmac->adapter, 0); return 0; }
static int pm3393_interrupt_disable(struct cmac *cmac) { u32 elmer; /* PM3393 - Enabling HW interrupt blocks. */ pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0); pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0); pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0); pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0); pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0); pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0); pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0); /* PM3393 - Global interrupt enable */ pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0); /* ELMER - External chip interrupts. */ t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer &= ~ELMER0_GP_BIT1; t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer); /* TERMINATOR - PL_INTERUPTS_EXT */ /* DO NOT DISABLE TERMINATOR's EXTERNAL INTERRUPTS. ANOTHER CHIP * COULD WANT THEM ENABLED. We disable PM3393 at the ELMER level. */ return 0; }
/* * Enable interrupts for the PM3393 * * 1. Enable PM3393 BLOCK interrupts. * 2. Enable PM3393 Master Interrupt bit(INTE) * 3. Enable ELMER's PM3393 bit. * 4. Enable Terminator external interrupt. */ static int pm3393_interrupt_enable(struct cmac *cmac) { u32 pl_intr; /* PM3393 - Enabling all hardware block interrupts. */ pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0xffff); /* Don't interrupt on statistics overflow, we are polling */ pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0); pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0xffff); /* PM3393 - Global interrupt enable */ /* TBD XXX Disable for now until we figure out why error interrupts keep asserting. */ pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0 /*SUNI1x10GEXP_BITMSK_TOP_INTE */ ); /* TERMINATOR - PL_INTERUPTS_EXT */ pl_intr = readl(cmac->adapter->regs + A_PL_ENABLE); pl_intr |= F_PL_INTR_EXT; writel(pl_intr, cmac->adapter->regs + A_PL_ENABLE); return 0; }
static int pm3393_interrupt_disable(struct cmac *cmac) { u32 elmer; pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0); pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0); pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0); pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0); pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0); pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0); pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0); pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0); t1_tpi_read(cmac->adapter, A_ELMER0_INT_ENABLE, &elmer); elmer &= ~ELMER0_GP_BIT1; t1_tpi_write(cmac->adapter, A_ELMER0_INT_ENABLE, elmer); return 0; }
static int pm3393_interrupt_enable(struct cmac *cmac) { u32 pl_intr; pmwrite(cmac, SUNI1x10GEXP_REG_SERDES_3125_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_XRF_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_XRF_DIAG_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_RXOAM_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_0, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_1, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_2, 0); pmwrite(cmac, SUNI1x10GEXP_REG_MSTAT_INTERRUPT_MASK_3, 0); pmwrite(cmac, SUNI1x10GEXP_REG_IFLX_FIFO_OVERFLOW_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_PL4ODP_INTERRUPT_MASK, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_XTEF_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_TXOAM_INTERRUPT_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_RXXG_CONFIG_3, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_PL4IO_LOCK_DETECT_MASK, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_TXXG_CONFIG_3, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_PL4IDU_INTERRUPT_MASK, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_EFLX_FIFO_OVERFLOW_ERROR_ENABLE, 0xffff); pmwrite(cmac, SUNI1x10GEXP_REG_GLOBAL_INTERRUPT_ENABLE, 0 ); pl_intr = readl(cmac->adapter->regs + A_PL_ENABLE); pl_intr |= F_PL_INTR_EXT; writel(pl_intr, cmac->adapter->regs + A_PL_ENABLE); return 0; }