/*
- * Copyright (C) 2006-2007 Freescale Semicondutor, Inc. All rights reserved.
+ * Copyright (C) 2006-2009 Freescale Semicondutor, Inc. All rights reserved.
*
* Author: Shlomi Gridish <gridish@freescale.com>
* Li Yang <leoli@freescale.com>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/dma-mapping.h>
-#include <linux/fsl_devices.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/workqueue.h>
+#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#include <asm/uaccess.h>
#include <asm/qe.h>
#include <asm/ucc.h>
#include <asm/ucc_fast.h>
+#include <asm/machdep.h>
#include "ucc_geth.h"
-#include "ucc_geth_mii.h"
+#include "fsl_pq_mdio.h"
#undef DEBUG
}
#endif /* DEBUG */
-#ifdef CONFIG_UGETH_FILTERING
-static void enqueue(struct list_head *node, struct list_head *lh)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ugeth_lock, flags);
- list_add_tail(node, lh);
- spin_unlock_irqrestore(&ugeth_lock, flags);
-}
-#endif /* CONFIG_UGETH_FILTERING */
-
static struct list_head *dequeue(struct list_head *lh)
{
unsigned long flags;
{
struct sk_buff *skb = NULL;
- skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
- UCC_GETH_RX_DATA_BUF_ALIGNMENT);
-
+ skb = __skb_dequeue(&ugeth->rx_recycle);
+ if (!skb)
+ skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT);
if (skb == NULL)
return NULL;
(((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT -
1)));
- skb->dev = ugeth->dev;
+ skb->dev = ugeth->ndev;
out_be32(&((struct qe_bd __iomem *)bd)->buf,
- dma_map_single(&ugeth->dev->dev,
+ dma_map_single(ugeth->dev,
skb->data,
ugeth->ug_info->uf_info.max_rx_buf_length +
UCC_GETH_RX_DATA_BUF_ALIGNMENT,
u8 num_entries,
u32 thread_size,
u32 thread_alignment,
- enum qe_risc_allocation risc,
+ unsigned int risc,
int skip_page_for_first_entry)
{
u32 init_enet_offset;
static int return_init_enet_entries(struct ucc_geth_private *ugeth,
u32 *p_start,
u8 num_entries,
- enum qe_risc_allocation risc,
+ unsigned int risc,
int skip_page_for_first_entry)
{
u32 init_enet_offset;
u32 __iomem *p_start,
u8 num_entries,
u32 thread_size,
- enum qe_risc_allocation risc,
+ unsigned int risc,
int skip_page_for_first_entry)
{
u32 init_enet_offset;
}
#endif
-#ifdef CONFIG_UGETH_FILTERING
-static struct enet_addr_container *get_enet_addr_container(void)
-{
- struct enet_addr_container *enet_addr_cont;
-
- /* allocate memory */
- enet_addr_cont = kmalloc(sizeof(struct enet_addr_container), GFP_KERNEL);
- if (!enet_addr_cont) {
- ugeth_err("%s: No memory for enet_addr_container object.",
- __func__);
- return NULL;
- }
-
- return enet_addr_cont;
-}
-#endif /* CONFIG_UGETH_FILTERING */
-
static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont)
{
kfree(enet_addr_cont);
out_be16(®[2], ((u16)mac[1] << 8) | mac[0]);
}
-#ifdef CONFIG_UGETH_FILTERING
-static int hw_add_addr_in_paddr(struct ucc_geth_private *ugeth,
- u8 *p_enet_addr, u8 paddr_num)
-{
- struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
-
- if (!(paddr_num < NUM_OF_PADDRS)) {
- ugeth_warn("%s: Illegal paddr_num.", __func__);
- return -EINVAL;
- }
-
- p_82xx_addr_filt =
- (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
- addressfiltering;
-
- /* Ethernet frames are defined in Little Endian mode, */
- /* therefore to insert the address we reverse the bytes. */
- set_mac_addr(&p_82xx_addr_filt->paddr[paddr_num].h, p_enet_addr);
- return 0;
-}
-#endif /* CONFIG_UGETH_FILTERING */
-
static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num)
{
struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
/* Ethernet frames are defined in Little Endian mode,
- therefor to insert */
+ therefore to insert */
/* the address to the hash (Big Endian mode), we reverse the bytes.*/
set_mac_addr(&p_82xx_addr_filt->taddr.h, p_enet_addr);
QE_CR_PROTOCOL_ETHERNET, 0);
}
-#ifdef CONFIG_UGETH_MAGIC_PACKET
-static void magic_packet_detection_enable(struct ucc_geth_private *ugeth)
-{
- struct ucc_fast_private *uccf;
- struct ucc_geth __iomem *ug_regs;
- u32 maccfg2, uccm;
-
- uccf = ugeth->uccf;
- ug_regs = ugeth->ug_regs;
-
- /* Enable interrupts for magic packet detection */
- uccm = in_be32(uccf->p_uccm);
- uccm |= UCCE_MPD;
- out_be32(uccf->p_uccm, uccm);
-
- /* Enable magic packet detection */
- maccfg2 = in_be32(&ug_regs->maccfg2);
- maccfg2 |= MACCFG2_MPE;
- out_be32(&ug_regs->maccfg2, maccfg2);
-}
-
-static void magic_packet_detection_disable(struct ucc_geth_private *ugeth)
-{
- struct ucc_fast_private *uccf;
- struct ucc_geth __iomem *ug_regs;
- u32 maccfg2, uccm;
-
- uccf = ugeth->uccf;
- ug_regs = ugeth->ug_regs;
-
- /* Disable interrupts for magic packet detection */
- uccm = in_be32(uccf->p_uccm);
- uccm &= ~UCCE_MPD;
- out_be32(uccf->p_uccm, uccm);
-
- /* Disable magic packet detection */
- maccfg2 = in_be32(&ug_regs->maccfg2);
- maccfg2 &= ~MACCFG2_MPE;
- out_be32(&ug_regs->maccfg2, maccfg2);
-}
-#endif /* MAGIC_PACKET */
-
static inline int compare_addr(u8 **addr1, u8 **addr2)
{
return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS);
/* Hardware only if user handed pointer and driver actually
gathers hardware statistics */
- if (hardware_statistics && (in_be32(&uf_regs->upsmr) & UPSMR_HSE)) {
+ if (hardware_statistics &&
+ (in_be32(&uf_regs->upsmr) & UCC_GETH_UPSMR_HSE)) {
hardware_statistics->tx64 = in_be32(&ug_regs->tx64);
hardware_statistics->tx127 = in_be32(&ug_regs->tx127);
hardware_statistics->tx255 = in_be32(&ug_regs->tx255);
out_be32(uempr_register, value);
/* Set UPSMR register */
- value = in_be32(upsmr_register);
- value |= automatic_flow_control_mode;
- out_be32(upsmr_register, value);
+ setbits32(upsmr_register, automatic_flow_control_mode);
value = in_be32(maccfg1_register);
if (rx_flow_control_enable)
u32 __iomem *upsmr_register,
u16 __iomem *uescr_register)
{
- u32 upsmr_value = 0;
u16 uescr_value = 0;
+
/* Enable hardware statistics gathering if requested */
- if (enable_hardware_statistics) {
- upsmr_value = in_be32(upsmr_register);
- upsmr_value |= UPSMR_HSE;
- out_be32(upsmr_register, upsmr_value);
- }
+ if (enable_hardware_statistics)
+ setbits32(upsmr_register, UCC_GETH_UPSMR_HSE);
/* Clear hardware statistics counters */
uescr_value = in_be16(uescr_register);
{
/* Note: this function does not check if */
/* the parameters it receives are NULL */
- u16 temoder_value;
- u32 remoder_value;
if (enable_tx_firmware_statistics) {
out_be32(tx_rmon_base_ptr,
tx_firmware_statistics_structure_address);
- temoder_value = in_be16(temoder_register);
- temoder_value |= TEMODER_TX_RMON_STATISTICS_ENABLE;
- out_be16(temoder_register, temoder_value);
+ setbits16(temoder_register, TEMODER_TX_RMON_STATISTICS_ENABLE);
}
if (enable_rx_firmware_statistics) {
out_be32(rx_rmon_base_ptr,
rx_firmware_statistics_structure_address);
- remoder_value = in_be32(remoder_register);
- remoder_value |= REMODER_RX_RMON_STATISTICS_ENABLE;
- out_be32(remoder_register, remoder_value);
+ setbits32(remoder_register, REMODER_RX_RMON_STATISTICS_ENABLE);
}
return 0;
static int init_preamble_length(u8 preamble_length,
u32 __iomem *maccfg2_register)
{
- u32 value = 0;
-
if ((preamble_length < 3) || (preamble_length > 7))
return -EINVAL;
- value = in_be32(maccfg2_register);
- value &= ~MACCFG2_PREL_MASK;
- value |= (preamble_length << MACCFG2_PREL_SHIFT);
- out_be32(maccfg2_register, value);
+ clrsetbits_be32(maccfg2_register, MACCFG2_PREL_MASK,
+ preamble_length << MACCFG2_PREL_SHIFT);
+
return 0;
}
value = in_be32(upsmr_register);
if (reject_broadcast)
- value |= UPSMR_BRO;
+ value |= UCC_GETH_UPSMR_BRO;
else
- value &= ~UPSMR_BRO;
+ value &= ~UCC_GETH_UPSMR_BRO;
if (receive_short_frames)
- value |= UPSMR_RSH;
+ value |= UCC_GETH_UPSMR_RSH;
else
- value &= ~UPSMR_RSH;
+ value &= ~UCC_GETH_UPSMR_RSH;
if (promiscuous)
- value |= UPSMR_PRO;
+ value |= UCC_GETH_UPSMR_PRO;
else
- value &= ~UPSMR_PRO;
+ value &= ~UCC_GETH_UPSMR_PRO;
out_be32(upsmr_register, value);
u16 __iomem *mrblr_register)
{
/* max_rx_buf_len value must be a multiple of 128 */
- if ((max_rx_buf_len == 0)
- || (max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT))
+ if ((max_rx_buf_len == 0) ||
+ (max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT))
return -EINVAL;
out_be16(mrblr_register, max_rx_buf_len);
struct ucc_geth __iomem *ug_regs;
struct ucc_fast __iomem *uf_regs;
int ret_val;
- u32 upsmr, maccfg2, tbiBaseAddress;
+ u32 upsmr, maccfg2;
u16 value;
ugeth_vdbg("%s: IN", __func__);
/* Set UPSMR */
upsmr = in_be32(&uf_regs->upsmr);
- upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
+ upsmr &= ~(UCC_GETH_UPSMR_RPM | UCC_GETH_UPSMR_R10M |
+ UCC_GETH_UPSMR_TBIM | UCC_GETH_UPSMR_RMM);
if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
- upsmr |= UPSMR_RPM;
+ if (ugeth->phy_interface != PHY_INTERFACE_MODE_RMII)
+ upsmr |= UCC_GETH_UPSMR_RPM;
switch (ugeth->max_speed) {
case SPEED_10:
- upsmr |= UPSMR_R10M;
+ upsmr |= UCC_GETH_UPSMR_R10M;
/* FALLTHROUGH */
case SPEED_100:
if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI)
- upsmr |= UPSMR_RMM;
+ upsmr |= UCC_GETH_UPSMR_RMM;
}
}
if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
- upsmr |= UPSMR_TBIM;
+ upsmr |= UCC_GETH_UPSMR_TBIM;
}
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII))
+ upsmr |= UCC_GETH_UPSMR_SGMM;
+
out_be32(&uf_regs->upsmr, upsmr);
/* Disable autonegotiation in tbi mode, because by default it
/* Note that this depends on proper setting in utbipar register. */
if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
- tbiBaseAddress = in_be32(&ug_regs->utbipar);
- tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
- tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
- value = ugeth->phydev->bus->read(ugeth->phydev->bus,
- (u8) tbiBaseAddress, ENET_TBI_MII_CR);
+ struct ucc_geth_info *ug_info = ugeth->ug_info;
+ struct phy_device *tbiphy;
+
+ if (!ug_info->tbi_node)
+ ugeth_warn("TBI mode requires that the device "
+ "tree specify a tbi-handle\n");
+
+ tbiphy = of_phy_find_device(ug_info->tbi_node);
+ if (!tbiphy)
+ ugeth_warn("Could not get TBI device\n");
+
+ value = phy_read(tbiphy, ENET_TBI_MII_CR);
value &= ~0x1000; /* Turn off autonegotiation */
- ugeth->phydev->bus->write(ugeth->phydev->bus,
- (u8) tbiBaseAddress, ENET_TBI_MII_CR, value);
+ phy_write(tbiphy, ENET_TBI_MII_CR, value);
}
init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
return 0;
}
-/* Called every time the controller might need to be made
- * aware of new link state. The PHY code conveys this
- * information through variables in the ugeth structure, and this
- * function converts those variables into the appropriate
- * register values, and can bring down the device if needed.
- */
-
-static void adjust_link(struct net_device *dev)
-{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
- struct ucc_geth __iomem *ug_regs;
- struct ucc_fast __iomem *uf_regs;
- struct phy_device *phydev = ugeth->phydev;
- unsigned long flags;
- int new_state = 0;
-
- ug_regs = ugeth->ug_regs;
- uf_regs = ugeth->uccf->uf_regs;
-
- spin_lock_irqsave(&ugeth->lock, flags);
-
- if (phydev->link) {
- u32 tempval = in_be32(&ug_regs->maccfg2);
- u32 upsmr = in_be32(&uf_regs->upsmr);
- /* Now we make sure that we can be in full duplex mode.
- * If not, we operate in half-duplex mode. */
- if (phydev->duplex != ugeth->oldduplex) {
- new_state = 1;
- if (!(phydev->duplex))
- tempval &= ~(MACCFG2_FDX);
- else
- tempval |= MACCFG2_FDX;
- ugeth->oldduplex = phydev->duplex;
- }
-
- if (phydev->speed != ugeth->oldspeed) {
- new_state = 1;
- switch (phydev->speed) {
- case SPEED_1000:
- tempval = ((tempval &
- ~(MACCFG2_INTERFACE_MODE_MASK)) |
- MACCFG2_INTERFACE_MODE_BYTE);
- break;
- case SPEED_100:
- case SPEED_10:
- tempval = ((tempval &
- ~(MACCFG2_INTERFACE_MODE_MASK)) |
- MACCFG2_INTERFACE_MODE_NIBBLE);
- /* if reduced mode, re-set UPSMR.R10M */
- if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
- (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
- (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
- (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
- (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
- (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
- if (phydev->speed == SPEED_10)
- upsmr |= UPSMR_R10M;
- else
- upsmr &= ~(UPSMR_R10M);
- }
- break;
- default:
- if (netif_msg_link(ugeth))
- ugeth_warn(
- "%s: Ack! Speed (%d) is not 10/100/1000!",
- dev->name, phydev->speed);
- break;
- }
- ugeth->oldspeed = phydev->speed;
- }
-
- out_be32(&ug_regs->maccfg2, tempval);
- out_be32(&uf_regs->upsmr, upsmr);
-
- if (!ugeth->oldlink) {
- new_state = 1;
- ugeth->oldlink = 1;
- }
- } else if (ugeth->oldlink) {
- new_state = 1;
- ugeth->oldlink = 0;
- ugeth->oldspeed = 0;
- ugeth->oldduplex = -1;
- }
-
- if (new_state && netif_msg_link(ugeth))
- phy_print_status(phydev);
-
- spin_unlock_irqrestore(&ugeth->lock, flags);
-}
-
-/* Configure the PHY for dev.
- * returns 0 if success. -1 if failure
- */
-static int init_phy(struct net_device *dev)
-{
- struct ucc_geth_private *priv = netdev_priv(dev);
- struct phy_device *phydev;
- char phy_id[BUS_ID_SIZE];
-
- priv->oldlink = 0;
- priv->oldspeed = 0;
- priv->oldduplex = -1;
-
- snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, priv->ug_info->mdio_bus,
- priv->ug_info->phy_address);
-
- phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
-
- if (IS_ERR(phydev)) {
- printk("%s: Could not attach to PHY\n", dev->name);
- return PTR_ERR(phydev);
- }
-
- phydev->supported &= (ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full);
-
- if (priv->max_speed == SPEED_1000)
- phydev->supported |= ADVERTISED_1000baseT_Full;
-
- phydev->advertising = phydev->supported;
-
- priv->phydev = phydev;
-
- return 0;
-}
-
-
-
static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
{
struct ucc_fast_private *uccf;
uccf = ugeth->uccf;
/* Mask GRACEFUL STOP TX interrupt bit and clear it */
- temp = in_be32(uccf->p_uccm);
- temp &= ~UCCE_GRA;
- out_be32(uccf->p_uccm, temp);
- out_be32(uccf->p_ucce, UCCE_GRA); /* clear by writing 1 */
+ clrbits32(uccf->p_uccm, UCC_GETH_UCCE_GRA);
+ out_be32(uccf->p_ucce, UCC_GETH_UCCE_GRA); /* clear by writing 1 */
/* Issue host command */
cecr_subblock =
do {
msleep(10);
temp = in_be32(uccf->p_ucce);
- } while (!(temp & UCCE_GRA) && --i);
+ } while (!(temp & UCC_GETH_UCCE_GRA) && --i);
uccf->stopped_tx = 1;
return 0;
}
-static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth)
+static int ugeth_graceful_stop_rx(struct ucc_geth_private *ugeth)
{
struct ucc_fast_private *uccf;
u32 cecr_subblock;
}
-static int ugeth_disable(struct ucc_geth_private * ugeth, enum comm_dir mode)
+static int ugeth_disable(struct ucc_geth_private *ugeth, enum comm_dir mode)
{
struct ucc_fast_private *uccf;
return 0;
}
-static void ugeth_dump_regs(struct ucc_geth_private *ugeth)
+static void ugeth_quiesce(struct ucc_geth_private *ugeth)
{
-#ifdef DEBUG
- ucc_fast_dump_regs(ugeth->uccf);
- dump_regs(ugeth);
- dump_bds(ugeth);
-#endif
-}
+ /* Prevent any further xmits, plus detach the device. */
+ netif_device_detach(ugeth->ndev);
-#ifdef CONFIG_UGETH_FILTERING
-static int ugeth_ext_filtering_serialize_tad(struct ucc_geth_tad_params *
- p_UccGethTadParams,
- struct qe_fltr_tad *qe_fltr_tad)
-{
- u16 temp;
-
- /* Zero serialized TAD */
- memset(qe_fltr_tad, 0, QE_FLTR_TAD_SIZE);
-
- qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_V; /* Must have this */
- if (p_UccGethTadParams->rx_non_dynamic_extended_features_mode ||
- (p_UccGethTadParams->vtag_op != UCC_GETH_VLAN_OPERATION_TAGGED_NOP)
- || (p_UccGethTadParams->vnontag_op !=
- UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP)
- )
- qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_EF;
- if (p_UccGethTadParams->reject_frame)
- qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_REJ;
- temp =
- (u16) (((u16) p_UccGethTadParams->
- vtag_op) << UCC_GETH_TAD_VTAG_OP_SHIFT);
- qe_fltr_tad->serialized[0] |= (u8) (temp >> 8); /* upper bits */
-
- qe_fltr_tad->serialized[1] |= (u8) (temp & 0x00ff); /* lower bits */
- if (p_UccGethTadParams->vnontag_op ==
- UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT)
- qe_fltr_tad->serialized[1] |= UCC_GETH_TAD_V_NON_VTAG_OP;
- qe_fltr_tad->serialized[1] |=
- p_UccGethTadParams->rqos << UCC_GETH_TAD_RQOS_SHIFT;
-
- qe_fltr_tad->serialized[2] |=
- p_UccGethTadParams->vpri << UCC_GETH_TAD_V_PRIORITY_SHIFT;
- /* upper bits */
- qe_fltr_tad->serialized[2] |= (u8) (p_UccGethTadParams->vid >> 8);
- /* lower bits */
- qe_fltr_tad->serialized[3] |= (u8) (p_UccGethTadParams->vid & 0x00ff);
+ /* Wait for any current xmits to finish. */
+ netif_tx_disable(ugeth->ndev);
- return 0;
+ /* Disable the interrupt to avoid NAPI rescheduling. */
+ disable_irq(ugeth->ug_info->uf_info.irq);
+
+ /* Stop NAPI, and possibly wait for its completion. */
+ napi_disable(&ugeth->napi);
}
-static struct enet_addr_container_t
- *ugeth_82xx_filtering_get_match_addr_in_hash(struct ucc_geth_private *ugeth,
- struct enet_addr *p_enet_addr)
+static void ugeth_activate(struct ucc_geth_private *ugeth)
{
- struct enet_addr_container *enet_addr_cont;
- struct list_head *p_lh;
- u16 i, num;
- int32_t j;
- u8 *p_counter;
+ napi_enable(&ugeth->napi);
+ enable_irq(ugeth->ug_info->uf_info.irq);
+ netif_device_attach(ugeth->ndev);
+}
- if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
- p_lh = &ugeth->group_hash_q;
- p_counter = &(ugeth->numGroupAddrInHash);
- } else {
- p_lh = &ugeth->ind_hash_q;
- p_counter = &(ugeth->numIndAddrInHash);
- }
+/* Called every time the controller might need to be made
+ * aware of new link state. The PHY code conveys this
+ * information through variables in the ugeth structure, and this
+ * function converts those variables into the appropriate
+ * register values, and can bring down the device if needed.
+ */
- if (!p_lh)
- return NULL;
+static void adjust_link(struct net_device *dev)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(dev);
+ struct ucc_geth __iomem *ug_regs;
+ struct ucc_fast __iomem *uf_regs;
+ struct phy_device *phydev = ugeth->phydev;
+ int new_state = 0;
- num = *p_counter;
+ ug_regs = ugeth->ug_regs;
+ uf_regs = ugeth->uccf->uf_regs;
- for (i = 0; i < num; i++) {
- enet_addr_cont =
- (struct enet_addr_container *)
- ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
- for (j = ENET_NUM_OCTETS_PER_ADDRESS - 1; j >= 0; j--) {
- if ((*p_enet_addr)[j] != (enet_addr_cont->address)[j])
+ if (phydev->link) {
+ u32 tempval = in_be32(&ug_regs->maccfg2);
+ u32 upsmr = in_be32(&uf_regs->upsmr);
+ /* Now we make sure that we can be in full duplex mode.
+ * If not, we operate in half-duplex mode. */
+ if (phydev->duplex != ugeth->oldduplex) {
+ new_state = 1;
+ if (!(phydev->duplex))
+ tempval &= ~(MACCFG2_FDX);
+ else
+ tempval |= MACCFG2_FDX;
+ ugeth->oldduplex = phydev->duplex;
+ }
+
+ if (phydev->speed != ugeth->oldspeed) {
+ new_state = 1;
+ switch (phydev->speed) {
+ case SPEED_1000:
+ tempval = ((tempval &
+ ~(MACCFG2_INTERFACE_MODE_MASK)) |
+ MACCFG2_INTERFACE_MODE_BYTE);
break;
- if (j == 0)
- return enet_addr_cont; /* Found */
+ case SPEED_100:
+ case SPEED_10:
+ tempval = ((tempval &
+ ~(MACCFG2_INTERFACE_MODE_MASK)) |
+ MACCFG2_INTERFACE_MODE_NIBBLE);
+ /* if reduced mode, re-set UPSMR.R10M */
+ if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) ||
+ (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
+ if (phydev->speed == SPEED_10)
+ upsmr |= UCC_GETH_UPSMR_R10M;
+ else
+ upsmr &= ~UCC_GETH_UPSMR_R10M;
+ }
+ break;
+ default:
+ if (netif_msg_link(ugeth))
+ ugeth_warn(
+ "%s: Ack! Speed (%d) is not 10/100/1000!",
+ dev->name, phydev->speed);
+ break;
+ }
+ ugeth->oldspeed = phydev->speed;
}
- enqueue(p_lh, &enet_addr_cont->node); /* Put it back */
+
+ if (!ugeth->oldlink) {
+ new_state = 1;
+ ugeth->oldlink = 1;
+ }
+
+ if (new_state) {
+ /*
+ * To change the MAC configuration we need to disable
+ * the controller. To do so, we have to either grab
+ * ugeth->lock, which is a bad idea since 'graceful
+ * stop' commands might take quite a while, or we can
+ * quiesce driver's activity.
+ */
+ ugeth_quiesce(ugeth);
+ ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
+
+ out_be32(&ug_regs->maccfg2, tempval);
+ out_be32(&uf_regs->upsmr, upsmr);
+
+ ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
+ ugeth_activate(ugeth);
+ }
+ } else if (ugeth->oldlink) {
+ new_state = 1;
+ ugeth->oldlink = 0;
+ ugeth->oldspeed = 0;
+ ugeth->oldduplex = -1;
}
- return NULL;
+
+ if (new_state && netif_msg_link(ugeth))
+ phy_print_status(phydev);
}
-static int ugeth_82xx_filtering_add_addr_in_hash(struct ucc_geth_private *ugeth,
- struct enet_addr *p_enet_addr)
+/* Initialize TBI PHY interface for communicating with the
+ * SERDES lynx PHY on the chip. We communicate with this PHY
+ * through the MDIO bus on each controller, treating it as a
+ * "normal" PHY at the address found in the UTBIPA register. We assume
+ * that the UTBIPA register is valid. Either the MDIO bus code will set
+ * it to a value that doesn't conflict with other PHYs on the bus, or the
+ * value doesn't matter, as there are no other PHYs on the bus.
+ */
+static void uec_configure_serdes(struct net_device *dev)
{
- enum ucc_geth_enet_address_recognition_location location;
- struct enet_addr_container *enet_addr_cont;
- struct list_head *p_lh;
- u8 i;
- u32 limit;
- u8 *p_counter;
+ struct ucc_geth_private *ugeth = netdev_priv(dev);
+ struct ucc_geth_info *ug_info = ugeth->ug_info;
+ struct phy_device *tbiphy;
- if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
- p_lh = &ugeth->group_hash_q;
- limit = ugeth->ug_info->maxGroupAddrInHash;
- location =
- UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH;
- p_counter = &(ugeth->numGroupAddrInHash);
- } else {
- p_lh = &ugeth->ind_hash_q;
- limit = ugeth->ug_info->maxIndAddrInHash;
- location =
- UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH;
- p_counter = &(ugeth->numIndAddrInHash);
+ if (!ug_info->tbi_node) {
+ dev_warn(&dev->dev, "SGMII mode requires that the device "
+ "tree specify a tbi-handle\n");
+ return;
}
- if ((enet_addr_cont =
- ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) {
- list_add(p_lh, &enet_addr_cont->node); /* Put it back */
- return 0;
+ tbiphy = of_phy_find_device(ug_info->tbi_node);
+ if (!tbiphy) {
+ dev_err(&dev->dev, "error: Could not get TBI device\n");
+ return;
}
- if ((!p_lh) || (!(*p_counter < limit)))
- return -EBUSY;
- if (!(enet_addr_cont = get_enet_addr_container()))
- return -ENOMEM;
- for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)
- (enet_addr_cont->address)[i] = (*p_enet_addr)[i];
- enet_addr_cont->location = location;
- enqueue(p_lh, &enet_addr_cont->node); /* Put it back */
- ++(*p_counter);
- hw_add_addr_in_hash(ugeth, enet_addr_cont->address);
- return 0;
-}
+ /*
+ * If the link is already up, we must already be ok, and don't need to
+ * configure and reset the TBI<->SerDes link. Maybe U-Boot configured
+ * everything for us? Resetting it takes the link down and requires
+ * several seconds for it to come back.
+ */
+ if (phy_read(tbiphy, ENET_TBI_MII_SR) & TBISR_LSTATUS)
+ return;
-static int ugeth_82xx_filtering_clear_addr_in_hash(struct ucc_geth_private *ugeth,
- struct enet_addr *p_enet_addr)
-{
- struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt;
- struct enet_addr_container *enet_addr_cont;
- struct ucc_fast_private *uccf;
- enum comm_dir comm_dir;
- u16 i, num;
- struct list_head *p_lh;
- u32 *addr_h, *addr_l;
- u8 *p_counter;
+ /* Single clk mode, mii mode off(for serdes communication) */
+ phy_write(tbiphy, ENET_TBI_MII_ANA, TBIANA_SETTINGS);
- uccf = ugeth->uccf;
+ phy_write(tbiphy, ENET_TBI_MII_TBICON, TBICON_CLK_SELECT);
- p_82xx_addr_filt =
- (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram->
- addressfiltering;
+ phy_write(tbiphy, ENET_TBI_MII_CR, TBICR_SETTINGS);
+}
- if (!
- (enet_addr_cont =
- ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr)))
- return -ENOENT;
+/* Configure the PHY for dev.
+ * returns 0 if success. -1 if failure
+ */
+static int init_phy(struct net_device *dev)
+{
+ struct ucc_geth_private *priv = netdev_priv(dev);
+ struct ucc_geth_info *ug_info = priv->ug_info;
+ struct phy_device *phydev;
- /* It's been found and removed from the CQ. */
- /* Now destroy its container */
- put_enet_addr_container(enet_addr_cont);
+ priv->oldlink = 0;
+ priv->oldspeed = 0;
+ priv->oldduplex = -1;
- if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
- addr_h = &(p_82xx_addr_filt->gaddr_h);
- addr_l = &(p_82xx_addr_filt->gaddr_l);
- p_lh = &ugeth->group_hash_q;
- p_counter = &(ugeth->numGroupAddrInHash);
- } else {
- addr_h = &(p_82xx_addr_filt->iaddr_h);
- addr_l = &(p_82xx_addr_filt->iaddr_l);
- p_lh = &ugeth->ind_hash_q;
- p_counter = &(ugeth->numIndAddrInHash);
+ phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0,
+ priv->phy_interface);
+ if (!phydev)
+ phydev = of_phy_connect_fixed_link(dev, &adjust_link,
+ priv->phy_interface);
+ if (!phydev) {
+ dev_err(&dev->dev, "Could not attach to PHY\n");
+ return -ENODEV;
}
- comm_dir = 0;
- if (uccf->enabled_tx)
- comm_dir |= COMM_DIR_TX;
- if (uccf->enabled_rx)
- comm_dir |= COMM_DIR_RX;
- if (comm_dir)
- ugeth_disable(ugeth, comm_dir);
+ if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
+ uec_configure_serdes(dev);
- /* Clear the hash table. */
- out_be32(addr_h, 0x00000000);
- out_be32(addr_l, 0x00000000);
+ phydev->supported &= (ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full);
- /* Add all remaining CQ elements back into hash */
- num = --(*p_counter);
- for (i = 0; i < num; i++) {
- enet_addr_cont =
- (struct enet_addr_container *)
- ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
- hw_add_addr_in_hash(ugeth, enet_addr_cont->address);
- enqueue(p_lh, &enet_addr_cont->node); /* Put it back */
- }
+ if (priv->max_speed == SPEED_1000)
+ phydev->supported |= ADVERTISED_1000baseT_Full;
- if (comm_dir)
- ugeth_enable(ugeth, comm_dir);
+ phydev->advertising = phydev->supported;
+
+ priv->phydev = phydev;
return 0;
}
-#endif /* CONFIG_UGETH_FILTERING */
+
+static void ugeth_dump_regs(struct ucc_geth_private *ugeth)
+{
+#ifdef DEBUG
+ ucc_fast_dump_regs(ugeth->uccf);
+ dump_regs(ugeth);
+ dump_bds(ugeth);
+#endif
+}
static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private *
ugeth,
return 0;
}
-#ifdef CONFIG_UGETH_FILTERING
-static int ugeth_82xx_filtering_add_addr_in_paddr(struct ucc_geth_private *ugeth,
- struct enet_addr *p_enet_addr,
- u8 paddr_num)
-{
- int i;
-
- if ((*p_enet_addr)[0] & ENET_GROUP_ADDR)
- ugeth_warn
- ("%s: multicast address added to paddr will have no "
- "effect - is this what you wanted?",
- __func__);
-
- ugeth->indAddrRegUsed[paddr_num] = 1; /* mark this paddr as used */
- /* store address in our database */
- for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)
- ugeth->paddr[paddr_num][i] = (*p_enet_addr)[i];
- /* put in hardware */
- return hw_add_addr_in_paddr(ugeth, p_enet_addr, paddr_num);
-}
-#endif /* CONFIG_UGETH_FILTERING */
-
static int ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *ugeth,
u8 paddr_num)
{
continue;
for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
if (ugeth->tx_skbuff[i][j]) {
- dma_unmap_single(&ugeth->dev->dev,
+ dma_unmap_single(ugeth->dev,
in_be32(&((struct qe_bd __iomem *)bd)->buf),
(in_be32((u32 __iomem *)bd) &
BD_LENGTH_MASK),
bd = ugeth->p_rx_bd_ring[i];
for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) {
if (ugeth->rx_skbuff[i][j]) {
- dma_unmap_single(&ugeth->dev->dev,
+ dma_unmap_single(ugeth->dev,
in_be32(&((struct qe_bd __iomem *)bd)->buf),
ugeth->ug_info->
uf_info.max_rx_buf_length +
iounmap(ugeth->ug_regs);
ugeth->ug_regs = NULL;
}
+
+ skb_queue_purge(&ugeth->rx_recycle);
}
static void ucc_geth_set_multi(struct net_device *dev)
{
struct ucc_geth_private *ugeth;
- struct dev_mc_list *dmi;
+ struct netdev_hw_addr *ha;
struct ucc_fast __iomem *uf_regs;
struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt;
- int i;
ugeth = netdev_priv(dev);
uf_regs = ugeth->uccf->uf_regs;
if (dev->flags & IFF_PROMISC) {
-
- out_be32(&uf_regs->upsmr, in_be32(&uf_regs->upsmr) | UPSMR_PRO);
-
+ setbits32(&uf_regs->upsmr, UCC_GETH_UPSMR_PRO);
} else {
-
- out_be32(&uf_regs->upsmr, in_be32(&uf_regs->upsmr)&~UPSMR_PRO);
+ clrbits32(&uf_regs->upsmr, UCC_GETH_UPSMR_PRO);
p_82xx_addr_filt =
(struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth->
out_be32(&p_82xx_addr_filt->gaddr_h, 0x0);
out_be32(&p_82xx_addr_filt->gaddr_l, 0x0);
- dmi = dev->mc_list;
-
- for (i = 0; i < dev->mc_count; i++, dmi = dmi->next) {
-
+ netdev_for_each_mc_addr(ha, dev) {
/* Only support group multicast for now.
*/
- if (!(dmi->dmi_addr[0] & 1))
+ if (!(ha->addr[0] & 1))
continue;
/* Ask CPM to run CRC and set bit in
* filter mask.
*/
- hw_add_addr_in_hash(ugeth, dmi->dmi_addr);
+ hw_add_addr_in_hash(ugeth, ha->addr);
}
}
}
{
struct ucc_geth __iomem *ug_regs = ugeth->ug_regs;
struct phy_device *phydev = ugeth->phydev;
- u32 tempval;
ugeth_vdbg("%s: IN", __func__);
out_be32(ugeth->uccf->p_ucce, 0xffffffff);
/* Disable Rx and Tx */
- tempval = in_be32(&ug_regs->maccfg1);
- tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
- out_be32(&ug_regs->maccfg1, tempval);
+ clrbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
+
+ phy_disconnect(ugeth->phydev);
+ ugeth->phydev = NULL;
ucc_geth_memclean(ugeth);
}
}
if ((ug_info->numStationAddresses !=
- UCC_GETH_NUM_OF_STATION_ADDRESSES_1)
- && ug_info->rxExtendedFiltering) {
+ UCC_GETH_NUM_OF_STATION_ADDRESSES_1) &&
+ ug_info->rxExtendedFiltering) {
if (netif_msg_probe(ugeth))
ugeth_err("%s: Number of station addresses greater than 1 "
"not allowed in extended parsing mode.",
/* Generate uccm_mask for receive */
uf_info->uccm_mask = ug_info->eventRegMask & UCCE_OTHER;/* Errors */
for (i = 0; i < ug_info->numQueuesRx; i++)
- uf_info->uccm_mask |= (UCCE_RXBF_SINGLE_MASK << i);
+ uf_info->uccm_mask |= (UCC_GETH_UCCE_RXF0 << i);
for (i = 0; i < ug_info->numQueuesTx; i++)
- uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
+ uf_info->uccm_mask |= (UCC_GETH_UCCE_TXB0 << i);
/* Initialize the general fast UCC block. */
if (ucc_fast_init(uf_info, &ugeth->uccf)) {
if (netif_msg_probe(ugeth))
return -ENOMEM;
}
+ /* read the number of risc engines, update the riscTx and riscRx
+ * if there are 4 riscs in QE
+ */
+ if (qe_get_num_of_risc() == 4) {
+ ug_info->riscTx = QE_RISC_ALLOCATION_FOUR_RISCS;
+ ug_info->riscRx = QE_RISC_ALLOCATION_FOUR_RISCS;
+ }
+
ugeth->ug_regs = ioremap(uf_info->regs, sizeof(*ugeth->ug_regs));
if (!ugeth->ug_regs) {
if (netif_msg_probe(ugeth))
return -ENOMEM;
}
+ skb_queue_head_init(&ugeth->rx_recycle);
+
return 0;
}
struct ucc_geth __iomem *ug_regs;
int ret_val = -EINVAL;
u32 remoder = UCC_GETH_REMODER_INIT;
- u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
+ u32 init_enet_pram_offset, cecr_subblock, command;
u32 ifstat, i, j, size, l2qt, l3qt, length;
u16 temoder = UCC_GETH_TEMODER_INIT;
u16 test;
UCC_GETH_NUM_OF_STATION_ADDRESSES_1);
ugeth->rx_extended_features = ugeth->rx_non_dynamic_extended_features ||
- (ug_info->vlanOperationTagged != UCC_GETH_VLAN_OPERATION_TAGGED_NOP)
- || (ug_info->vlanOperationNonTagged !=
- UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
+ (ug_info->vlanOperationTagged != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) ||
+ (ug_info->vlanOperationNonTagged !=
+ UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
init_default_reg_vals(&uf_regs->upsmr,
&ug_regs->maccfg1, &ug_regs->maccfg2);
&uf_regs->upsmr,
&ug_regs->uempr, &ug_regs->maccfg1);
- maccfg1 = in_be32(&ug_regs->maccfg1);
- maccfg1 |= MACCFG1_ENABLE_RX;
- maccfg1 |= MACCFG1_ENABLE_TX;
- out_be32(&ug_regs->maccfg1, maccfg1);
+ setbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
/* Set IPGIFG */
/* For more details see the hardware spec. */
ugeth->p_init_enet_param_shadow->rgftgfrxglobal |=
ugeth->rx_glbl_pram_offset | ug_info->riscRx;
if ((ug_info->largestexternallookupkeysize !=
- QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE)
- && (ug_info->largestexternallookupkeysize !=
- QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
- && (ug_info->largestexternallookupkeysize !=
- QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) {
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE) &&
+ (ug_info->largestexternallookupkeysize !=
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES) &&
+ (ug_info->largestexternallookupkeysize !=
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) {
if (netif_msg_ifup(ugeth))
ugeth_err("%s: Invalid largest External Lookup Key Size.",
__func__);
return 0;
}
-static int ucc_geth_close(struct net_device *dev);
-static int ucc_geth_open(struct net_device *dev);
-
-/* Reopen device. This will reset the MAC and PHY. */
-static void ucc_geth_timeout_work(struct work_struct *work)
-{
- struct ucc_geth_private *ugeth;
- struct net_device *dev;
-
- ugeth = container_of(work, struct ucc_geth_private, timeout_work);
- dev = ugeth->dev;
-
- ugeth_vdbg("%s: IN", __func__);
-
- dev->stats.tx_errors++;
-
- ugeth_dump_regs(ugeth);
-
- if (dev->flags & IFF_UP) {
- /*
- * Must reset MAC *and* PHY. This is done by reopening
- * the device.
- */
- ucc_geth_close(dev);
- ucc_geth_open(dev);
- }
-
- netif_tx_schedule_all(dev);
-}
-
-/*
- * ucc_geth_timeout gets called when a packet has not been
- * transmitted after a set amount of time.
- */
-static void ucc_geth_timeout(struct net_device *dev)
-{
- struct ucc_geth_private *ugeth = netdev_priv(dev);
-
- netif_carrier_off(dev);
- schedule_work(&ugeth->timeout_work);
-}
-
/* This is called by the kernel when a frame is ready for transmission. */
/* It is pointed to by the dev->hard_start_xmit function pointer */
static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
u8 __iomem *bd; /* BD pointer */
u32 bd_status;
u8 txQ = 0;
+ unsigned long flags;
ugeth_vdbg("%s: IN", __func__);
- spin_lock_irq(&ugeth->lock);
+ spin_lock_irqsave(&ugeth->lock, flags);
dev->stats.tx_bytes += skb->len;
/* set up the buffer descriptor */
out_be32(&((struct qe_bd __iomem *)bd)->buf,
- dma_map_single(&ugeth->dev->dev, skb->data,
+ dma_map_single(ugeth->dev, skb->data,
skb->len, DMA_TO_DEVICE));
/* printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data); */
/* set bd status and length */
out_be32((u32 __iomem *)bd, bd_status);
- dev->trans_start = jiffies;
-
/* Move to next BD in the ring */
if (!(bd_status & T_W))
bd += sizeof(struct qe_bd);
uccf = ugeth->uccf;
out_be16(uccf->p_utodr, UCC_FAST_TOD);
#endif
- spin_unlock_irq(&ugeth->lock);
+ spin_unlock_irqrestore(&ugeth->lock, flags);
- return 0;
+ return NETDEV_TX_OK;
}
static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit)
ugeth_vdbg("%s: IN", __func__);
- dev = ugeth->dev;
+ dev = ugeth->ndev;
/* collect received buffers */
bd = ugeth->rxBd[rxQ];
if (netif_msg_rx_err(ugeth))
ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
__func__, __LINE__, (u32) skb);
- if (skb)
- dev_kfree_skb_any(skb);
+ if (skb) {
+ skb->data = skb->head + NET_SKB_PAD;
+ __skb_queue_head(&ugeth->rx_recycle, skb);
+ }
ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
dev->stats.rx_dropped++;
skb_put(skb, length);
/* Tell the skb what kind of packet this is */
- skb->protocol = eth_type_trans(skb, ugeth->dev);
+ skb->protocol = eth_type_trans(skb, ugeth->ndev);
dev->stats.rx_bytes += length;
/* Send the packet up the stack */
/* Normal processing. */
while ((bd_status & T_R) == 0) {
+ struct sk_buff *skb;
+
/* BD contains already transmitted buffer. */
/* Handle the transmitted buffer and release */
/* the BD to be used with the current frame */
- if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0))
+ skb = ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]];
+ if (!skb)
break;
dev->stats.tx_packets++;
- /* Free the sk buffer associated with this TxBD */
- dev_kfree_skb_irq(ugeth->
- tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]);
+ if (skb_queue_len(&ugeth->rx_recycle) < RX_BD_RING_LEN &&
+ skb_recycle_check(skb,
+ ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT))
+ __skb_queue_head(&ugeth->rx_recycle, skb);
+ else
+ dev_kfree_skb(skb);
+
ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
ugeth->skb_dirtytx[txQ] =
(ugeth->skb_dirtytx[txQ] +
static int ucc_geth_poll(struct napi_struct *napi, int budget)
{
struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi);
- struct net_device *dev = ugeth->dev;
struct ucc_geth_info *ug_info;
int howmany, i;
ug_info = ugeth->ug_info;
+ /* Tx event processing */
+ spin_lock(&ugeth->lock);
+ for (i = 0; i < ug_info->numQueuesTx; i++)
+ ucc_geth_tx(ugeth->ndev, i);
+ spin_unlock(&ugeth->lock);
+
howmany = 0;
for (i = 0; i < ug_info->numQueuesRx; i++)
howmany += ucc_geth_rx(ugeth, i, budget - howmany);
if (howmany < budget) {
- struct ucc_fast_private *uccf;
- u32 uccm;
-
- netif_rx_complete(dev, napi);
- uccf = ugeth->uccf;
- uccm = in_be32(uccf->p_uccm);
- uccm |= UCCE_RX_EVENTS;
- out_be32(uccf->p_uccm, uccm);
+ napi_complete(napi);
+ setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS | UCCE_TX_EVENTS);
}
return howmany;
struct ucc_geth_info *ug_info;
register u32 ucce;
register u32 uccm;
- register u32 tx_mask;
- u8 i;
ugeth_vdbg("%s: IN", __func__);
out_be32(uccf->p_ucce, ucce);
/* check for receive events that require processing */
- if (ucce & UCCE_RX_EVENTS) {
- if (netif_rx_schedule_prep(dev, &ugeth->napi)) {
- uccm &= ~UCCE_RX_EVENTS;
+ if (ucce & (UCCE_RX_EVENTS | UCCE_TX_EVENTS)) {
+ if (napi_schedule_prep(&ugeth->napi)) {
+ uccm &= ~(UCCE_RX_EVENTS | UCCE_TX_EVENTS);
out_be32(uccf->p_uccm, uccm);
- __netif_rx_schedule(dev, &ugeth->napi);
- }
- }
-
- /* Tx event processing */
- if (ucce & UCCE_TX_EVENTS) {
- spin_lock(&ugeth->lock);
- tx_mask = UCCE_TXBF_SINGLE_MASK;
- for (i = 0; i < ug_info->numQueuesTx; i++) {
- if (ucce & tx_mask)
- ucc_geth_tx(dev, i);
- ucce &= ~tx_mask;
- tx_mask <<= 1;
+ __napi_schedule(&ugeth->napi);
}
- spin_unlock(&ugeth->lock);
}
/* Errors and other events */
if (ucce & UCCE_OTHER) {
- if (ucce & UCCE_BSY) {
+ if (ucce & UCC_GETH_UCCE_BSY)
dev->stats.rx_errors++;
- }
- if (ucce & UCCE_TXE) {
+ if (ucce & UCC_GETH_UCCE_TXE)
dev->stats.tx_errors++;
- }
}
return IRQ_HANDLED;
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
-/* Called when something needs to use the ethernet device */
-/* Returns 0 for success. */
-static int ucc_geth_open(struct net_device *dev)
+static int ucc_geth_set_mac_addr(struct net_device *dev, void *p)
{
struct ucc_geth_private *ugeth = netdev_priv(dev);
- int err;
+ struct sockaddr *addr = p;
- ugeth_vdbg("%s: IN", __func__);
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
- /* Test station address */
- if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
- if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Multicast address used for station address"
- " - is this what you wanted?", __func__);
- return -EINVAL;
- }
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ /*
+ * If device is not running, we will set mac addr register
+ * when opening the device.
+ */
+ if (!netif_running(dev))
+ return 0;
+
+ spin_lock_irq(&ugeth->lock);
+ init_mac_station_addr_regs(dev->dev_addr[0],
+ dev->dev_addr[1],
+ dev->dev_addr[2],
+ dev->dev_addr[3],
+ dev->dev_addr[4],
+ dev->dev_addr[5],
+ &ugeth->ug_regs->macstnaddr1,
+ &ugeth->ug_regs->macstnaddr2);
+ spin_unlock_irq(&ugeth->lock);
+
+ return 0;
+}
+
+static int ucc_geth_init_mac(struct ucc_geth_private *ugeth)
+{
+ struct net_device *dev = ugeth->ndev;
+ int err;
err = ucc_struct_init(ugeth);
if (err) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
- goto out_err_stop;
+ ugeth_err("%s: Cannot configure internal struct, "
+ "aborting.", dev->name);
+ goto err;
}
- napi_enable(&ugeth->napi);
-
err = ucc_geth_startup(ugeth);
if (err) {
if (netif_msg_ifup(ugeth))
ugeth_err("%s: Cannot configure net device, aborting.",
dev->name);
- goto out_err;
+ goto err;
}
err = adjust_enet_interface(ugeth);
if (netif_msg_ifup(ugeth))
ugeth_err("%s: Cannot configure net device, aborting.",
dev->name);
- goto out_err;
+ goto err;
}
/* Set MACSTNADDR1, MACSTNADDR2 */
&ugeth->ug_regs->macstnaddr1,
&ugeth->ug_regs->macstnaddr2);
- err = init_phy(dev);
+ err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
if (err) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
- goto out_err;
+ ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
+ goto err;
}
- phy_start(ugeth->phydev);
+ return 0;
+err:
+ ucc_geth_stop(ugeth);
+ return err;
+}
- err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
+/* Called when something needs to use the ethernet device */
+/* Returns 0 for success. */
+static int ucc_geth_open(struct net_device *dev)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(dev);
+ int err;
+
+ ugeth_vdbg("%s: IN", __func__);
+
+ /* Test station address */
+ if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Multicast address used for station "
+ "address - is this what you wanted?",
+ __func__);
+ return -EINVAL;
+ }
+
+ err = init_phy(dev);
if (err) {
if (netif_msg_ifup(ugeth))
- ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
- goto out_err;
+ ugeth_err("%s: Cannot initialize PHY, aborting.",
+ dev->name);
+ return err;
+ }
+
+ err = ucc_geth_init_mac(ugeth);
+ if (err) {
+ if (netif_msg_ifup(ugeth))
+ ugeth_err("%s: Cannot initialize MAC, aborting.",
+ dev->name);
+ goto err;
}
err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler,
if (netif_msg_ifup(ugeth))
ugeth_err("%s: Cannot get IRQ for net device, aborting.",
dev->name);
- goto out_err;
+ goto err;
}
+ phy_start(ugeth->phydev);
+ napi_enable(&ugeth->napi);
netif_start_queue(dev);
+ device_set_wakeup_capable(&dev->dev,
+ qe_alive_during_sleep() || ugeth->phydev->irq);
+ device_set_wakeup_enable(&dev->dev, ugeth->wol_en);
+
return err;
-out_err:
- napi_disable(&ugeth->napi);
-out_err_stop:
+err:
ucc_geth_stop(ugeth);
return err;
}
ucc_geth_stop(ugeth);
- free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
-
- phy_disconnect(ugeth->phydev);
- ugeth->phydev = NULL;
+ free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev);
netif_stop_queue(dev);
return 0;
}
+/* Reopen device. This will reset the MAC and PHY. */
+static void ucc_geth_timeout_work(struct work_struct *work)
+{
+ struct ucc_geth_private *ugeth;
+ struct net_device *dev;
+
+ ugeth = container_of(work, struct ucc_geth_private, timeout_work);
+ dev = ugeth->ndev;
+
+ ugeth_vdbg("%s: IN", __func__);
+
+ dev->stats.tx_errors++;
+
+ ugeth_dump_regs(ugeth);
+
+ if (dev->flags & IFF_UP) {
+ /*
+ * Must reset MAC *and* PHY. This is done by reopening
+ * the device.
+ */
+ ucc_geth_close(dev);
+ ucc_geth_open(dev);
+ }
+
+ netif_tx_schedule_all(dev);
+}
+
+/*
+ * ucc_geth_timeout gets called when a packet has not been
+ * transmitted after a set amount of time.
+ */
+static void ucc_geth_timeout(struct net_device *dev)
+{
+ struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+ netif_carrier_off(dev);
+ schedule_work(&ugeth->timeout_work);
+}
+
+
+#ifdef CONFIG_PM
+
+static int ucc_geth_suspend(struct of_device *ofdev, pm_message_t state)
+{
+ struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+ struct ucc_geth_private *ugeth = netdev_priv(ndev);
+
+ if (!netif_running(ndev))
+ return 0;
+
+ netif_device_detach(ndev);
+ napi_disable(&ugeth->napi);
+
+ /*
+ * Disable the controller, otherwise we'll wakeup on any network
+ * activity.
+ */
+ ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
+
+ if (ugeth->wol_en & WAKE_MAGIC) {
+ setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD);
+ setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE);
+ ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX);
+ } else if (!(ugeth->wol_en & WAKE_PHY)) {
+ phy_stop(ugeth->phydev);
+ }
+
+ return 0;
+}
+
+static int ucc_geth_resume(struct of_device *ofdev)
+{
+ struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+ struct ucc_geth_private *ugeth = netdev_priv(ndev);
+ int err;
+
+ if (!netif_running(ndev))
+ return 0;
+
+ if (qe_alive_during_sleep()) {
+ if (ugeth->wol_en & WAKE_MAGIC) {
+ ucc_fast_disable(ugeth->uccf, COMM_DIR_RX_AND_TX);
+ clrbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE);
+ clrbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD);
+ }
+ ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
+ } else {
+ /*
+ * Full reinitialization is required if QE shuts down
+ * during sleep.
+ */
+ ucc_geth_memclean(ugeth);
+
+ err = ucc_geth_init_mac(ugeth);
+ if (err) {
+ ugeth_err("%s: Cannot initialize MAC, aborting.",
+ ndev->name);
+ return err;
+ }
+ }
+
+ ugeth->oldlink = 0;
+ ugeth->oldspeed = 0;
+ ugeth->oldduplex = -1;
+
+ phy_stop(ugeth->phydev);
+ phy_start(ugeth->phydev);
+
+ napi_enable(&ugeth->napi);
+ netif_device_attach(ndev);
+
+ return 0;
+}
+
+#else
+#define ucc_geth_suspend NULL
+#define ucc_geth_resume NULL
+#endif
+
static phy_interface_t to_phy_interface(const char *phy_connection_type)
{
if (strcasecmp(phy_connection_type, "mii") == 0)
return PHY_INTERFACE_MODE_RGMII_RXID;
if (strcasecmp(phy_connection_type, "rtbi") == 0)
return PHY_INTERFACE_MODE_RTBI;
+ if (strcasecmp(phy_connection_type, "sgmii") == 0)
+ return PHY_INTERFACE_MODE_SGMII;
return PHY_INTERFACE_MODE_MII;
}
+static const struct net_device_ops ucc_geth_netdev_ops = {
+ .ndo_open = ucc_geth_open,
+ .ndo_stop = ucc_geth_close,
+ .ndo_start_xmit = ucc_geth_start_xmit,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_mac_address = ucc_geth_set_mac_addr,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_multicast_list = ucc_geth_set_multi,
+ .ndo_tx_timeout = ucc_geth_timeout,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = ucc_netpoll,
+#endif
+};
+
static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match)
{
struct device *device = &ofdev->dev;
struct device_node *np = ofdev->node;
- struct device_node *mdio;
struct net_device *dev = NULL;
struct ucc_geth_private *ugeth = NULL;
struct ucc_geth_info *ug_info;
struct resource res;
- struct device_node *phy;
int err, ucc_num, max_speed = 0;
- const phandle *ph;
- const u32 *fixed_link;
const unsigned int *prop;
const char *sprop;
const void *mac_addr;
PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII,
PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII,
PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI,
+ PHY_INTERFACE_MODE_SGMII,
};
ugeth_vdbg("%s: IN", __func__);
prop = of_get_property(np, "tx-clock", NULL);
if (!prop) {
printk(KERN_ERR
- "ucc_geth: mising tx-clock-name property\n");
+ "ucc_geth: missing tx-clock-name property\n");
return -EINVAL;
}
if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) {
ug_info->uf_info.regs = res.start;
ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
- fixed_link = of_get_property(np, "fixed-link", NULL);
- if (fixed_link) {
- snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "0");
- ug_info->phy_address = fixed_link[0];
- phy = NULL;
- } else {
- ph = of_get_property(np, "phy-handle", NULL);
- phy = of_find_node_by_phandle(*ph);
-
- if (phy == NULL)
- return -ENODEV;
-
- /* set the PHY address */
- prop = of_get_property(phy, "reg", NULL);
- if (prop == NULL)
- return -1;
- ug_info->phy_address = *prop;
- /* Set the bus id */
- mdio = of_get_parent(phy);
+ ug_info->phy_node = of_parse_phandle(np, "phy-handle", 0);
- if (mdio == NULL)
- return -1;
-
- err = of_address_to_resource(mdio, 0, &res);
- of_node_put(mdio);
-
- if (err)
- return -1;
-
- snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "%x", res.start);
- }
+ /* Find the TBI PHY node. If it's not there, we don't support SGMII */
+ ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
/* get the phy interface type, or default to MII */
prop = of_get_property(np, "phy-connection-type", NULL);
if (!prop) {
/* handle interface property present in old trees */
- prop = of_get_property(phy, "interface", NULL);
+ prop = of_get_property(ug_info->phy_node, "interface", NULL);
if (prop != NULL) {
phy_interface = enet_to_phy_interface[*prop];
max_speed = enet_to_speed[*prop];
case PHY_INTERFACE_MODE_RGMII_TXID:
case PHY_INTERFACE_MODE_TBI:
case PHY_INTERFACE_MODE_RTBI:
+ case PHY_INTERFACE_MODE_SGMII:
max_speed = SPEED_1000;
break;
default:
ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT;
ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT;
ug_info->numThreadsTx = UCC_GETH_NUM_OF_THREADS_4;
- ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4;
+
+ /* If QE's snum number is 46 which means we need to support
+ * 4 UECs at 1000Base-T simultaneously, we need to allocate
+ * more Threads to Rx.
+ */
+ if (qe_get_num_of_snums() == 46)
+ ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_6;
+ else
+ ug_info->numThreadsRx = UCC_GETH_NUM_OF_THREADS_4;
}
if (netif_msg_probe(&debug))
- printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
+ printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d)\n",
ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
ug_info->uf_info.irq);
/* Fill in the dev structure */
uec_set_ethtool_ops(dev);
- dev->open = ucc_geth_open;
- dev->hard_start_xmit = ucc_geth_start_xmit;
- dev->tx_timeout = ucc_geth_timeout;
+ dev->netdev_ops = &ucc_geth_netdev_ops;
dev->watchdog_timeo = TX_TIMEOUT;
INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work);
- netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT);
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = ucc_netpoll;
-#endif
- dev->stop = ucc_geth_close;
-// dev->change_mtu = ucc_geth_change_mtu;
+ netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, 64);
dev->mtu = 1500;
- dev->set_multicast_list = ucc_geth_set_multi;
ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT);
ugeth->phy_interface = phy_interface;
memcpy(dev->dev_addr, mac_addr, 6);
ugeth->ug_info = ug_info;
- ugeth->dev = dev;
+ ugeth->dev = device;
+ ugeth->ndev = dev;
+ ugeth->node = np;
return 0;
}
.match_table = ucc_geth_match,
.probe = ucc_geth_probe,
.remove = ucc_geth_remove,
+ .suspend = ucc_geth_suspend,
+ .resume = ucc_geth_resume,
};
static int __init ucc_geth_init(void)
{
int i, ret;
- ret = uec_mdio_init();
-
- if (ret)
- return ret;
-
if (netif_msg_drv(&debug))
printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
for (i = 0; i < 8; i++)
ret = of_register_platform_driver(&ucc_geth_driver);
- if (ret)
- uec_mdio_exit();
-
return ret;
}
static void __exit ucc_geth_exit(void)
{
of_unregister_platform_driver(&ucc_geth_driver);
- uec_mdio_exit();
}
module_init(ucc_geth_init);