trie_rebalance()
The key function for the dynamic trie after any change in the trie
- it is run to optimize and reorganize. Tt will walk the trie upwards
- towards the root from a given tnode, doing a resize() at each step
+ it is run to optimize and reorganize. It will walk the trie upwards
+ towards the root from a given tnode, doing a resize() at each step
to implement level compression.
resize()
depends on HAS_IOMEM
select NET_DSA
select NET_DSA_TAG_BRCM
- select FIXED_PHY if NET_DSA_BCM_SF2=y
+ select FIXED_PHY
select BCM7XXX_PHY
select MDIO_BCM_UNIMAC
---help---
tristate "Broadcom GENET internal MAC support"
select MII
select PHYLIB
- select FIXED_PHY if BCMGENET=y
+ select FIXED_PHY
select BCM7XXX_PHY
help
This driver supports the built-in Ethernet MACs found in the
depends on OF
select MII
select PHYLIB
- select FIXED_PHY if SYSTEMPORT=y
+ select FIXED_PHY
help
This driver supports the built-in Ethernet MACs found in the
Broadcom BCM7xxx Set Top Box family chipset using an internal
int err = -ENXIO;
const char *mac;
void __iomem *mem;
- unsigned int hw_q, queue_mask, q, num_queues, q_irq = 0;
+ unsigned int hw_q, queue_mask, q, num_queues;
struct clk *pclk, *hclk, *tx_clk;
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
* register mapping but we don't want to test the queue index then
* compute the corresponding register offset at run time.
*/
- for (hw_q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) {
+ for (hw_q = 0, q = 0; hw_q < MACB_MAX_QUEUES; ++hw_q) {
if (!(queue_mask & (1 << hw_q)))
continue;
- queue = &bp->queues[q_irq];
+ queue = &bp->queues[q];
queue->bp = bp;
if (hw_q) {
queue->ISR = GEM_ISR(hw_q - 1);
* must remove the optional gaps that could exist in the
* hardware queue mask.
*/
- queue->irq = platform_get_irq(pdev, q_irq);
+ queue->irq = platform_get_irq(pdev, q);
err = devm_request_irq(&pdev->dev, queue->irq, macb_interrupt,
0, dev->name, queue);
if (err) {
dev_err(&pdev->dev,
"Unable to request IRQ %d (error %d)\n",
queue->irq, err);
- goto err_out_free_irq;
+ goto err_out_free_netdev;
}
INIT_WORK(&queue->tx_error_task, macb_tx_error_task);
- q_irq++;
+ q++;
}
dev->irq = bp->queues[0].irq;
err = register_netdev(dev);
if (err) {
dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
- goto err_out_free_irq;
+ goto err_out_free_netdev;
}
err = macb_mii_init(bp);
err_out_unregister_netdev:
unregister_netdev(dev);
-err_out_free_irq:
- for (q = 0, queue = bp->queues; q < q_irq; ++q, ++queue)
- devm_free_irq(&pdev->dev, queue->irq, queue);
+err_out_free_netdev:
free_netdev(dev);
err_out_disable_clocks:
if (!IS_ERR(tx_clk))
{
struct net_device *dev;
struct macb *bp;
- struct macb_queue *queue;
- unsigned int q;
dev = platform_get_drvdata(pdev);
kfree(bp->mii_bus->irq);
mdiobus_free(bp->mii_bus);
unregister_netdev(dev);
- queue = bp->queues;
- for (q = 0; q < bp->num_queues; ++q, ++queue)
- devm_free_irq(&pdev->dev, queue->irq, queue);
- free_netdev(dev);
if (!IS_ERR(bp->tx_clk))
clk_disable_unprepare(bp->tx_clk);
clk_disable_unprepare(bp->hclk);
clk_disable_unprepare(bp->pclk);
+ free_netdev(dev);
}
return 0;
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
+#include <linux/jiffies.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/string.h>
static int __init
wait_eeprom_ready(struct net_device *dev)
{
- int timeout = jiffies;
+ unsigned long timeout = jiffies;
/* check to see if the EEPROM is ready,
* a timeout is used just in case EEPROM is ready when
* SI_BUSY in the PP_SelfST is clear
*/
while (readreg(dev, PP_SelfST) & SI_BUSY)
- if (jiffies - timeout >= 40)
+ if (time_after_eq(jiffies, timeout + 40))
return -1;
return 0;
}
{
struct net_local *lp = netdev_priv(dev);
unsigned int selfcontrol;
- int timenow = jiffies;
+ unsigned long timenow = jiffies;
/* control the DC to DC convertor in the SelfControl register.
* Note: This is hooked up to a general purpose pin, might not
* always be a DC to DC convertor.
writereg(dev, PP_SelfCTL, selfcontrol);
/* Wait for the DC/DC converter to power up - 500ms */
- while (jiffies - timenow < HZ)
+ while (time_before(jiffies, timenow + HZ))
;
}
0, 0, /* DSAP=0 & SSAP=0 fields */
0xf3, 0 /* Control (Test Req + P bit set) */
};
- long timenow = jiffies;
+ unsigned long timenow = jiffies;
writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON);
iowrite16(ETH_ZLEN, lp->virt_addr + TX_LEN_PORT);
/* Test to see if the chip has allocated memory for the packet */
- while (jiffies - timenow < 5)
+ while (time_before(jiffies, timenow + 5))
if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW)
break;
- if (jiffies - timenow >= 5)
+ if (time_after_eq(jiffies, timenow + 5))
return 0; /* this shouldn't happen */
/* Write the contents of the packet */
cs89_dbg(1, debug, "Sending test packet ");
/* wait a couple of jiffies for packet to be received */
- for (timenow = jiffies; jiffies - timenow < 3;)
+ for (timenow = jiffies; time_before(jiffies, timenow + 3);)
;
if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) {
cs89_dbg(1, cont, "succeeded\n");
detect_tp(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
- int timenow = jiffies;
+ unsigned long timenow = jiffies;
int fdx;
cs89_dbg(1, debug, "%s: Attempting TP\n", dev->name);
/* Delay for the hardware to work out if the TP cable is present
* - 150ms
*/
- for (timenow = jiffies; jiffies - timenow < 15;)
+ for (timenow = jiffies; time_before(jiffies, timenow + 15);)
;
if ((readreg(dev, PP_LineST) & LINK_OK) == 0)
return DETECTED_NONE;
if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) {
pr_info("%s: negotiating duplex...\n", dev->name);
while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) {
- if (jiffies - timenow > 4000) {
+ if (time_after(jiffies, timenow + 4000)) {
pr_err("**** Full / half duplex auto-negotiation timed out ****\n");
break;
}
{
#if !defined(CONFIG_MACH_MX31ADS)
struct net_local *lp = netdev_priv(dev);
- int reset_start_time;
+ unsigned long reset_start_time;
writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET);
/* Wait until the chip is reset */
reset_start_time = jiffies;
while ((readreg(dev, PP_SelfST) & INIT_DONE) == 0 &&
- jiffies - reset_start_time < 2)
+ time_before(jiffies, reset_start_time + 2))
;
#endif /* !CONFIG_MACH_MX31ADS */
}
if ((1 << (field & 0x3f)) > (PAGE_SIZE / dev_cap->bf_reg_size))
field = 3;
dev_cap->bf_regs_per_page = 1 << (field & 0x3f);
- mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n",
- dev_cap->bf_reg_size, dev_cap->bf_regs_per_page);
} else {
dev_cap->bf_reg_size = 0;
- mlx4_dbg(dev, "BlueFlame not available\n");
}
MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_SG_SQ_OFFSET);
goto out;
}
- mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n",
- dev_cap->bmme_flags, dev_cap->reserved_lkey);
-
/*
* Each UAR has 4 EQ doorbells; so if a UAR is reserved, then
* we can't use any EQs whose doorbell falls on that page,
else
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SYS_EQS;
+out:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+
+void mlx4_dev_cap_dump(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
+{
+ if (dev_cap->bf_reg_size > 0)
+ mlx4_dbg(dev, "BlueFlame available (reg size %d, regs/page %d)\n",
+ dev_cap->bf_reg_size, dev_cap->bf_regs_per_page);
+ else
+ mlx4_dbg(dev, "BlueFlame not available\n");
+
+ mlx4_dbg(dev, "Base MM extensions: flags %08x, rsvd L_Key %08x\n",
+ dev_cap->bmme_flags, dev_cap->reserved_lkey);
mlx4_dbg(dev, "Max ICM size %lld MB\n",
(unsigned long long) dev_cap->max_icm_sz >> 20);
mlx4_dbg(dev, "Max QPs: %d, reserved QPs: %d, entry size: %d\n",
dev_cap->dmfs_high_rate_qpn_base);
mlx4_dbg(dev, "DMFS high rate steer QPn range: %d\n",
dev_cap->dmfs_high_rate_qpn_range);
-
dump_dev_cap_flags(dev, dev_cap->flags);
dump_dev_cap_flags2(dev, dev_cap->flags2);
-
-out:
- mlx4_free_cmd_mailbox(dev, mailbox);
- return err;
}
int mlx4_QUERY_PORT(struct mlx4_dev *dev, int port, struct mlx4_port_cap *port_cap)
u32 cap_mask;
};
+void mlx4_dev_cap_dump(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap);
int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap);
int mlx4_QUERY_PORT(struct mlx4_dev *dev, int port, struct mlx4_port_cap *port_cap);
int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting\n");
return err;
}
+ mlx4_dev_cap_dump(dev, dev_cap);
if (dev_cap->min_page_sz > PAGE_SIZE) {
mlx4_err(dev, "HCA minimum page size of %d bigger than kernel PAGE_SIZE of %ld, aborting\n",
u8 total_vfs, int existing_vfs)
{
u64 dev_flags = dev->flags;
+ int err = 0;
- dev->dev_vfs = kzalloc(
- total_vfs * sizeof(*dev->dev_vfs),
- GFP_KERNEL);
+ atomic_inc(&pf_loading);
+ if (dev->flags & MLX4_FLAG_SRIOV) {
+ if (existing_vfs != total_vfs) {
+ mlx4_err(dev, "SR-IOV was already enabled, but with num_vfs (%d) different than requested (%d)\n",
+ existing_vfs, total_vfs);
+ total_vfs = existing_vfs;
+ }
+ }
+
+ dev->dev_vfs = kzalloc(total_vfs * sizeof(*dev->dev_vfs), GFP_KERNEL);
if (NULL == dev->dev_vfs) {
mlx4_err(dev, "Failed to allocate memory for VFs\n");
goto disable_sriov;
- } else if (!(dev->flags & MLX4_FLAG_SRIOV)) {
- int err = 0;
-
- atomic_inc(&pf_loading);
- if (existing_vfs) {
- if (existing_vfs != total_vfs)
- mlx4_err(dev, "SR-IOV was already enabled, but with num_vfs (%d) different than requested (%d)\n",
- existing_vfs, total_vfs);
- } else {
- mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", total_vfs);
- err = pci_enable_sriov(pdev, total_vfs);
- }
- if (err) {
- mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d)\n",
- err);
- atomic_dec(&pf_loading);
- goto disable_sriov;
- } else {
- mlx4_warn(dev, "Running in master mode\n");
- dev_flags |= MLX4_FLAG_SRIOV |
- MLX4_FLAG_MASTER;
- dev_flags &= ~MLX4_FLAG_SLAVE;
- dev->num_vfs = total_vfs;
- }
+ }
+
+ if (!(dev->flags & MLX4_FLAG_SRIOV)) {
+ mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", total_vfs);
+ err = pci_enable_sriov(pdev, total_vfs);
+ }
+ if (err) {
+ mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d)\n",
+ err);
+ goto disable_sriov;
+ } else {
+ mlx4_warn(dev, "Running in master mode\n");
+ dev_flags |= MLX4_FLAG_SRIOV |
+ MLX4_FLAG_MASTER;
+ dev_flags &= ~MLX4_FLAG_SLAVE;
+ dev->num_vfs = total_vfs;
}
return dev_flags;
disable_sriov:
+ atomic_dec(&pf_loading);
dev->num_vfs = 0;
kfree(dev->dev_vfs);
return dev_flags & ~MLX4_FLAG_MASTER;
}
if (total_vfs) {
- existing_vfs = pci_num_vf(pdev);
dev->flags = MLX4_FLAG_MASTER;
+ existing_vfs = pci_num_vf(pdev);
+ if (existing_vfs)
+ dev->flags |= MLX4_FLAG_SRIOV;
dev->num_vfs = total_vfs;
}
}
}
if (mlx4_is_master(dev)) {
+ /* when we hit the goto slave_start below, dev_cap already initialized */
if (!dev_cap) {
dev_cap = kzalloc(sizeof(*dev_cap), GFP_KERNEL);
if (mlx4_is_master(dev) && dev->num_vfs)
atomic_dec(&pf_loading);
+ kfree(dev_cap);
return 0;
err_port:
select CRC32
select MII
depends on (ARM || M32R || SUPERH || MIPS || BLACKFIN || \
- MN10300 || COLDFIRE || ARM64 || XTENSA || NIOS2)
+ MN10300 || COLDFIRE || ARM64 || XTENSA || NIOS2) && (!OF || GPIOLIB)
---help---
This is a driver for SMC's 91x series of Ethernet chipsets,
including the SMC91C94 and the SMC91C111. Say Y if you want it
if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) {
const char *rs;
- dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
err = of_property_read_string(np, "st,tx-retime-src", &rs);
- if (err < 0)
+ if (err < 0) {
dev_warn(dev, "Use internal clock source\n");
-
- if (!strcasecmp(rs, "clk_125"))
+ dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
+ } else if (!strcasecmp(rs, "clk_125")) {
dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125;
- else if (!strcasecmp(rs, "txclk"))
+ } else if (!strcasecmp(rs, "txclk")) {
dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK;
+ }
dwmac->speed = SPEED_1000;
}
struct list_head next;
};
-#define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_VNET_LE | IFF_MULTI_QUEUE)
+#define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_MULTI_QUEUE)
+
+#define MACVTAP_VNET_LE 0x80000000
static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val)
{
- return __virtio16_to_cpu(q->flags & IFF_VNET_LE, val);
+ return __virtio16_to_cpu(q->flags & MACVTAP_VNET_LE, val);
}
static inline __virtio16 cpu_to_macvtap16(struct macvtap_queue *q, u16 val)
{
- return __cpu_to_virtio16(q->flags & IFF_VNET_LE, val);
+ return __cpu_to_virtio16(q->flags & MACVTAP_VNET_LE, val);
}
static struct proto macvtap_proto = {
void __user *argp = (void __user *)arg;
struct ifreq __user *ifr = argp;
unsigned int __user *up = argp;
- unsigned int u;
+ unsigned short u;
int __user *sp = argp;
int s;
int ret;
if ((u & ~MACVTAP_FEATURES) != (IFF_NO_PI | IFF_TAP))
ret = -EINVAL;
else
- q->flags = u;
+ q->flags = (q->flags & ~MACVTAP_FEATURES) | u;
return ret;
}
ret = 0;
+ u = q->flags;
if (copy_to_user(&ifr->ifr_name, vlan->dev->name, IFNAMSIZ) ||
- put_user(q->flags, &ifr->ifr_flags))
+ put_user(u, &ifr->ifr_flags))
ret = -EFAULT;
macvtap_put_vlan(vlan);
rtnl_unlock();
q->vnet_hdr_sz = s;
return 0;
+ case TUNGETVNETLE:
+ s = !!(q->flags & MACVTAP_VNET_LE);
+ if (put_user(s, sp))
+ return -EFAULT;
+ return 0;
+
+ case TUNSETVNETLE:
+ if (get_user(s, sp))
+ return -EFAULT;
+ if (s)
+ q->flags |= MACVTAP_VNET_LE;
+ else
+ q->flags &= ~MACVTAP_VNET_LE;
+ return 0;
+
case TUNSETOFFLOAD:
/* let the user check for future flags */
if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
Supports the KSZ9021, VSC8201, KS8001 PHYs.
config FIXED_PHY
- bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
- depends on PHYLIB=y
+ tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
+ depends on PHYLIB
---help---
Adds the platform "fixed" MDIO Bus to cover the boards that use
PHYs that are not connected to the real MDIO bus.
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
-obj-$(CONFIG_FIXED_PHY) += fixed.o
+obj-$(CONFIG_FIXED_PHY) += fixed_phy.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
+++ /dev/null
-/*
- * Fixed MDIO bus (MDIO bus emulation with fixed PHYs)
- *
- * Author: Vitaly Bordug <vbordug@ru.mvista.com>
- * Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * Copyright (c) 2006-2007 MontaVista Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/list.h>
-#include <linux/mii.h>
-#include <linux/phy.h>
-#include <linux/phy_fixed.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-
-#define MII_REGS_NUM 29
-
-struct fixed_mdio_bus {
- int irqs[PHY_MAX_ADDR];
- struct mii_bus *mii_bus;
- struct list_head phys;
-};
-
-struct fixed_phy {
- int addr;
- u16 regs[MII_REGS_NUM];
- struct phy_device *phydev;
- struct fixed_phy_status status;
- int (*link_update)(struct net_device *, struct fixed_phy_status *);
- struct list_head node;
-};
-
-static struct platform_device *pdev;
-static struct fixed_mdio_bus platform_fmb = {
- .phys = LIST_HEAD_INIT(platform_fmb.phys),
-};
-
-static int fixed_phy_update_regs(struct fixed_phy *fp)
-{
- u16 bmsr = BMSR_ANEGCAPABLE;
- u16 bmcr = 0;
- u16 lpagb = 0;
- u16 lpa = 0;
-
- if (fp->status.duplex) {
- bmcr |= BMCR_FULLDPLX;
-
- switch (fp->status.speed) {
- case 1000:
- bmsr |= BMSR_ESTATEN;
- bmcr |= BMCR_SPEED1000;
- lpagb |= LPA_1000FULL;
- break;
- case 100:
- bmsr |= BMSR_100FULL;
- bmcr |= BMCR_SPEED100;
- lpa |= LPA_100FULL;
- break;
- case 10:
- bmsr |= BMSR_10FULL;
- lpa |= LPA_10FULL;
- break;
- default:
- pr_warn("fixed phy: unknown speed\n");
- return -EINVAL;
- }
- } else {
- switch (fp->status.speed) {
- case 1000:
- bmsr |= BMSR_ESTATEN;
- bmcr |= BMCR_SPEED1000;
- lpagb |= LPA_1000HALF;
- break;
- case 100:
- bmsr |= BMSR_100HALF;
- bmcr |= BMCR_SPEED100;
- lpa |= LPA_100HALF;
- break;
- case 10:
- bmsr |= BMSR_10HALF;
- lpa |= LPA_10HALF;
- break;
- default:
- pr_warn("fixed phy: unknown speed\n");
- return -EINVAL;
- }
- }
-
- if (fp->status.link)
- bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
-
- if (fp->status.pause)
- lpa |= LPA_PAUSE_CAP;
-
- if (fp->status.asym_pause)
- lpa |= LPA_PAUSE_ASYM;
-
- fp->regs[MII_PHYSID1] = 0;
- fp->regs[MII_PHYSID2] = 0;
-
- fp->regs[MII_BMSR] = bmsr;
- fp->regs[MII_BMCR] = bmcr;
- fp->regs[MII_LPA] = lpa;
- fp->regs[MII_STAT1000] = lpagb;
-
- return 0;
-}
-
-static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
-{
- struct fixed_mdio_bus *fmb = bus->priv;
- struct fixed_phy *fp;
-
- if (reg_num >= MII_REGS_NUM)
- return -1;
-
- /* We do not support emulating Clause 45 over Clause 22 register reads
- * return an error instead of bogus data.
- */
- switch (reg_num) {
- case MII_MMD_CTRL:
- case MII_MMD_DATA:
- return -1;
- default:
- break;
- }
-
- list_for_each_entry(fp, &fmb->phys, node) {
- if (fp->addr == phy_addr) {
- /* Issue callback if user registered it. */
- if (fp->link_update) {
- fp->link_update(fp->phydev->attached_dev,
- &fp->status);
- fixed_phy_update_regs(fp);
- }
- return fp->regs[reg_num];
- }
- }
-
- return 0xFFFF;
-}
-
-static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num,
- u16 val)
-{
- return 0;
-}
-
-/*
- * If something weird is required to be done with link/speed,
- * network driver is able to assign a function to implement this.
- * May be useful for PHY's that need to be software-driven.
- */
-int fixed_phy_set_link_update(struct phy_device *phydev,
- int (*link_update)(struct net_device *,
- struct fixed_phy_status *))
-{
- struct fixed_mdio_bus *fmb = &platform_fmb;
- struct fixed_phy *fp;
-
- if (!link_update || !phydev || !phydev->bus)
- return -EINVAL;
-
- list_for_each_entry(fp, &fmb->phys, node) {
- if (fp->addr == phydev->addr) {
- fp->link_update = link_update;
- fp->phydev = phydev;
- return 0;
- }
- }
-
- return -ENOENT;
-}
-EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
-
-int fixed_phy_add(unsigned int irq, int phy_addr,
- struct fixed_phy_status *status)
-{
- int ret;
- struct fixed_mdio_bus *fmb = &platform_fmb;
- struct fixed_phy *fp;
-
- fp = kzalloc(sizeof(*fp), GFP_KERNEL);
- if (!fp)
- return -ENOMEM;
-
- memset(fp->regs, 0xFF, sizeof(fp->regs[0]) * MII_REGS_NUM);
-
- fmb->irqs[phy_addr] = irq;
-
- fp->addr = phy_addr;
- fp->status = *status;
-
- ret = fixed_phy_update_regs(fp);
- if (ret)
- goto err_regs;
-
- list_add_tail(&fp->node, &fmb->phys);
-
- return 0;
-
-err_regs:
- kfree(fp);
- return ret;
-}
-EXPORT_SYMBOL_GPL(fixed_phy_add);
-
-void fixed_phy_del(int phy_addr)
-{
- struct fixed_mdio_bus *fmb = &platform_fmb;
- struct fixed_phy *fp, *tmp;
-
- list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
- if (fp->addr == phy_addr) {
- list_del(&fp->node);
- kfree(fp);
- return;
- }
- }
-}
-EXPORT_SYMBOL_GPL(fixed_phy_del);
-
-static int phy_fixed_addr;
-static DEFINE_SPINLOCK(phy_fixed_addr_lock);
-
-struct phy_device *fixed_phy_register(unsigned int irq,
- struct fixed_phy_status *status,
- struct device_node *np)
-{
- struct fixed_mdio_bus *fmb = &platform_fmb;
- struct phy_device *phy;
- int phy_addr;
- int ret;
-
- /* Get the next available PHY address, up to PHY_MAX_ADDR */
- spin_lock(&phy_fixed_addr_lock);
- if (phy_fixed_addr == PHY_MAX_ADDR) {
- spin_unlock(&phy_fixed_addr_lock);
- return ERR_PTR(-ENOSPC);
- }
- phy_addr = phy_fixed_addr++;
- spin_unlock(&phy_fixed_addr_lock);
-
- ret = fixed_phy_add(PHY_POLL, phy_addr, status);
- if (ret < 0)
- return ERR_PTR(ret);
-
- phy = get_phy_device(fmb->mii_bus, phy_addr, false);
- if (!phy || IS_ERR(phy)) {
- fixed_phy_del(phy_addr);
- return ERR_PTR(-EINVAL);
- }
-
- of_node_get(np);
- phy->dev.of_node = np;
-
- ret = phy_device_register(phy);
- if (ret) {
- phy_device_free(phy);
- of_node_put(np);
- fixed_phy_del(phy_addr);
- return ERR_PTR(ret);
- }
-
- return phy;
-}
-EXPORT_SYMBOL_GPL(fixed_phy_register);
-
-static int __init fixed_mdio_bus_init(void)
-{
- struct fixed_mdio_bus *fmb = &platform_fmb;
- int ret;
-
- pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
- if (IS_ERR(pdev)) {
- ret = PTR_ERR(pdev);
- goto err_pdev;
- }
-
- fmb->mii_bus = mdiobus_alloc();
- if (fmb->mii_bus == NULL) {
- ret = -ENOMEM;
- goto err_mdiobus_reg;
- }
-
- snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
- fmb->mii_bus->name = "Fixed MDIO Bus";
- fmb->mii_bus->priv = fmb;
- fmb->mii_bus->parent = &pdev->dev;
- fmb->mii_bus->read = &fixed_mdio_read;
- fmb->mii_bus->write = &fixed_mdio_write;
- fmb->mii_bus->irq = fmb->irqs;
-
- ret = mdiobus_register(fmb->mii_bus);
- if (ret)
- goto err_mdiobus_alloc;
-
- return 0;
-
-err_mdiobus_alloc:
- mdiobus_free(fmb->mii_bus);
-err_mdiobus_reg:
- platform_device_unregister(pdev);
-err_pdev:
- return ret;
-}
-module_init(fixed_mdio_bus_init);
-
-static void __exit fixed_mdio_bus_exit(void)
-{
- struct fixed_mdio_bus *fmb = &platform_fmb;
- struct fixed_phy *fp, *tmp;
-
- mdiobus_unregister(fmb->mii_bus);
- mdiobus_free(fmb->mii_bus);
- platform_device_unregister(pdev);
-
- list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
- list_del(&fp->node);
- kfree(fp);
- }
-}
-module_exit(fixed_mdio_bus_exit);
-
-MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
-MODULE_AUTHOR("Vitaly Bordug");
-MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Fixed MDIO bus (MDIO bus emulation with fixed PHYs)
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * Copyright (c) 2006-2007 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/phy_fixed.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#define MII_REGS_NUM 29
+
+struct fixed_mdio_bus {
+ int irqs[PHY_MAX_ADDR];
+ struct mii_bus *mii_bus;
+ struct list_head phys;
+};
+
+struct fixed_phy {
+ int addr;
+ u16 regs[MII_REGS_NUM];
+ struct phy_device *phydev;
+ struct fixed_phy_status status;
+ int (*link_update)(struct net_device *, struct fixed_phy_status *);
+ struct list_head node;
+};
+
+static struct platform_device *pdev;
+static struct fixed_mdio_bus platform_fmb = {
+ .phys = LIST_HEAD_INIT(platform_fmb.phys),
+};
+
+static int fixed_phy_update_regs(struct fixed_phy *fp)
+{
+ u16 bmsr = BMSR_ANEGCAPABLE;
+ u16 bmcr = 0;
+ u16 lpagb = 0;
+ u16 lpa = 0;
+
+ if (fp->status.duplex) {
+ bmcr |= BMCR_FULLDPLX;
+
+ switch (fp->status.speed) {
+ case 1000:
+ bmsr |= BMSR_ESTATEN;
+ bmcr |= BMCR_SPEED1000;
+ lpagb |= LPA_1000FULL;
+ break;
+ case 100:
+ bmsr |= BMSR_100FULL;
+ bmcr |= BMCR_SPEED100;
+ lpa |= LPA_100FULL;
+ break;
+ case 10:
+ bmsr |= BMSR_10FULL;
+ lpa |= LPA_10FULL;
+ break;
+ default:
+ pr_warn("fixed phy: unknown speed\n");
+ return -EINVAL;
+ }
+ } else {
+ switch (fp->status.speed) {
+ case 1000:
+ bmsr |= BMSR_ESTATEN;
+ bmcr |= BMCR_SPEED1000;
+ lpagb |= LPA_1000HALF;
+ break;
+ case 100:
+ bmsr |= BMSR_100HALF;
+ bmcr |= BMCR_SPEED100;
+ lpa |= LPA_100HALF;
+ break;
+ case 10:
+ bmsr |= BMSR_10HALF;
+ lpa |= LPA_10HALF;
+ break;
+ default:
+ pr_warn("fixed phy: unknown speed\n");
+ return -EINVAL;
+ }
+ }
+
+ if (fp->status.link)
+ bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
+
+ if (fp->status.pause)
+ lpa |= LPA_PAUSE_CAP;
+
+ if (fp->status.asym_pause)
+ lpa |= LPA_PAUSE_ASYM;
+
+ fp->regs[MII_PHYSID1] = 0;
+ fp->regs[MII_PHYSID2] = 0;
+
+ fp->regs[MII_BMSR] = bmsr;
+ fp->regs[MII_BMCR] = bmcr;
+ fp->regs[MII_LPA] = lpa;
+ fp->regs[MII_STAT1000] = lpagb;
+
+ return 0;
+}
+
+static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
+{
+ struct fixed_mdio_bus *fmb = bus->priv;
+ struct fixed_phy *fp;
+
+ if (reg_num >= MII_REGS_NUM)
+ return -1;
+
+ /* We do not support emulating Clause 45 over Clause 22 register reads
+ * return an error instead of bogus data.
+ */
+ switch (reg_num) {
+ case MII_MMD_CTRL:
+ case MII_MMD_DATA:
+ return -1;
+ default:
+ break;
+ }
+
+ list_for_each_entry(fp, &fmb->phys, node) {
+ if (fp->addr == phy_addr) {
+ /* Issue callback if user registered it. */
+ if (fp->link_update) {
+ fp->link_update(fp->phydev->attached_dev,
+ &fp->status);
+ fixed_phy_update_regs(fp);
+ }
+ return fp->regs[reg_num];
+ }
+ }
+
+ return 0xFFFF;
+}
+
+static int fixed_mdio_write(struct mii_bus *bus, int phy_addr, int reg_num,
+ u16 val)
+{
+ return 0;
+}
+
+/*
+ * If something weird is required to be done with link/speed,
+ * network driver is able to assign a function to implement this.
+ * May be useful for PHY's that need to be software-driven.
+ */
+int fixed_phy_set_link_update(struct phy_device *phydev,
+ int (*link_update)(struct net_device *,
+ struct fixed_phy_status *))
+{
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ struct fixed_phy *fp;
+
+ if (!link_update || !phydev || !phydev->bus)
+ return -EINVAL;
+
+ list_for_each_entry(fp, &fmb->phys, node) {
+ if (fp->addr == phydev->addr) {
+ fp->link_update = link_update;
+ fp->phydev = phydev;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
+
+int fixed_phy_add(unsigned int irq, int phy_addr,
+ struct fixed_phy_status *status)
+{
+ int ret;
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ struct fixed_phy *fp;
+
+ fp = kzalloc(sizeof(*fp), GFP_KERNEL);
+ if (!fp)
+ return -ENOMEM;
+
+ memset(fp->regs, 0xFF, sizeof(fp->regs[0]) * MII_REGS_NUM);
+
+ fmb->irqs[phy_addr] = irq;
+
+ fp->addr = phy_addr;
+ fp->status = *status;
+
+ ret = fixed_phy_update_regs(fp);
+ if (ret)
+ goto err_regs;
+
+ list_add_tail(&fp->node, &fmb->phys);
+
+ return 0;
+
+err_regs:
+ kfree(fp);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fixed_phy_add);
+
+void fixed_phy_del(int phy_addr)
+{
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ struct fixed_phy *fp, *tmp;
+
+ list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
+ if (fp->addr == phy_addr) {
+ list_del(&fp->node);
+ kfree(fp);
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(fixed_phy_del);
+
+static int phy_fixed_addr;
+static DEFINE_SPINLOCK(phy_fixed_addr_lock);
+
+struct phy_device *fixed_phy_register(unsigned int irq,
+ struct fixed_phy_status *status,
+ struct device_node *np)
+{
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ struct phy_device *phy;
+ int phy_addr;
+ int ret;
+
+ /* Get the next available PHY address, up to PHY_MAX_ADDR */
+ spin_lock(&phy_fixed_addr_lock);
+ if (phy_fixed_addr == PHY_MAX_ADDR) {
+ spin_unlock(&phy_fixed_addr_lock);
+ return ERR_PTR(-ENOSPC);
+ }
+ phy_addr = phy_fixed_addr++;
+ spin_unlock(&phy_fixed_addr_lock);
+
+ ret = fixed_phy_add(PHY_POLL, phy_addr, status);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ phy = get_phy_device(fmb->mii_bus, phy_addr, false);
+ if (!phy || IS_ERR(phy)) {
+ fixed_phy_del(phy_addr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ of_node_get(np);
+ phy->dev.of_node = np;
+
+ ret = phy_device_register(phy);
+ if (ret) {
+ phy_device_free(phy);
+ of_node_put(np);
+ fixed_phy_del(phy_addr);
+ return ERR_PTR(ret);
+ }
+
+ return phy;
+}
+EXPORT_SYMBOL_GPL(fixed_phy_register);
+
+static int __init fixed_mdio_bus_init(void)
+{
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ int ret;
+
+ pdev = platform_device_register_simple("Fixed MDIO bus", 0, NULL, 0);
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ goto err_pdev;
+ }
+
+ fmb->mii_bus = mdiobus_alloc();
+ if (fmb->mii_bus == NULL) {
+ ret = -ENOMEM;
+ goto err_mdiobus_reg;
+ }
+
+ snprintf(fmb->mii_bus->id, MII_BUS_ID_SIZE, "fixed-0");
+ fmb->mii_bus->name = "Fixed MDIO Bus";
+ fmb->mii_bus->priv = fmb;
+ fmb->mii_bus->parent = &pdev->dev;
+ fmb->mii_bus->read = &fixed_mdio_read;
+ fmb->mii_bus->write = &fixed_mdio_write;
+ fmb->mii_bus->irq = fmb->irqs;
+
+ ret = mdiobus_register(fmb->mii_bus);
+ if (ret)
+ goto err_mdiobus_alloc;
+
+ return 0;
+
+err_mdiobus_alloc:
+ mdiobus_free(fmb->mii_bus);
+err_mdiobus_reg:
+ platform_device_unregister(pdev);
+err_pdev:
+ return ret;
+}
+module_init(fixed_mdio_bus_init);
+
+static void __exit fixed_mdio_bus_exit(void)
+{
+ struct fixed_mdio_bus *fmb = &platform_fmb;
+ struct fixed_phy *fp, *tmp;
+
+ mdiobus_unregister(fmb->mii_bus);
+ mdiobus_free(fmb->mii_bus);
+ platform_device_unregister(pdev);
+
+ list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
+ list_del(&fp->node);
+ kfree(fp);
+ }
+}
+module_exit(fixed_mdio_bus_exit);
+
+MODULE_DESCRIPTION("Fixed MDIO bus (MDIO bus emulation with fixed PHYs)");
+MODULE_AUTHOR("Vitaly Bordug");
+MODULE_LICENSE("GPL");
* overload it to mean fasync when stored there.
*/
#define TUN_FASYNC IFF_ATTACH_QUEUE
+/* High bits in flags field are unused. */
+#define TUN_VNET_LE 0x80000000
#define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \
- IFF_VNET_LE | IFF_MULTI_QUEUE)
+ IFF_MULTI_QUEUE)
#define GOODCOPY_LEN 128
#define FLT_EXACT_COUNT 8
static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val)
{
- return __virtio16_to_cpu(tun->flags & IFF_VNET_LE, val);
+ return __virtio16_to_cpu(tun->flags & TUN_VNET_LE, val);
}
static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val)
{
- return __cpu_to_virtio16(tun->flags & IFF_VNET_LE, val);
+ return __cpu_to_virtio16(tun->flags & TUN_VNET_LE, val);
}
static inline u32 tun_hashfn(u32 rxhash)
int sndbuf;
int vnet_hdr_sz;
unsigned int ifindex;
+ int le;
int ret;
if (cmd == TUNSETIFF || cmd == TUNSETQUEUE || _IOC_TYPE(cmd) == 0x89) {
tun->vnet_hdr_sz = vnet_hdr_sz;
break;
+ case TUNGETVNETLE:
+ le = !!(tun->flags & TUN_VNET_LE);
+ if (put_user(le, (int __user *)argp))
+ ret = -EFAULT;
+ break;
+
+ case TUNSETVNETLE:
+ if (get_user(le, (int __user *)argp)) {
+ ret = -EFAULT;
+ break;
+ }
+ if (le)
+ tun->flags |= TUN_VNET_LE;
+ else
+ tun->flags &= ~TUN_VNET_LE;
+ break;
+
case TUNATTACHFILTER:
/* Can be set only for TAPs */
ret = -EINVAL;
struct device_node;
-#ifdef CONFIG_FIXED_PHY
+#if IS_ENABLED(CONFIG_FIXED_PHY)
extern int fixed_phy_add(unsigned int irq, int phy_id,
struct fixed_phy_status *status);
extern struct phy_device *fixed_phy_register(unsigned int irq,
#define TUNSETQUEUE _IOW('T', 217, int)
#define TUNSETIFINDEX _IOW('T', 218, unsigned int)
#define TUNGETFILTER _IOR('T', 219, struct sock_fprog)
+#define TUNSETVNETLE _IOW('T', 220, int)
+#define TUNGETVNETLE _IOR('T', 221, int)
/* TUNSETIFF ifr flags */
#define IFF_TUN 0x0001
#define IFF_ONE_QUEUE 0x2000
#define IFF_VNET_HDR 0x4000
#define IFF_TUN_EXCL 0x8000
-#define IFF_VNET_LE 0x10000
#define IFF_MULTI_QUEUE 0x0100
#define IFF_ATTACH_QUEUE 0x0200
#define IFF_DETACH_QUEUE 0x0400
struct ip_tunnel *tunnel = netdev_priv(dev);
const struct iphdr *tnl_params;
- skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM));
- if (IS_ERR(skb))
- goto out;
-
if (dev->header_ops) {
/* Need space for new headers */
if (skb_cow_head(skb, dev->needed_headroom -
* to gre header.
*/
skb_pull(skb, tunnel->hlen + sizeof(struct iphdr));
+ skb_reset_mac_header(skb);
} else {
if (skb_cow_head(skb, dev->needed_headroom))
goto free_skb;
tnl_params = &tunnel->parms.iph;
}
+ skb = gre_handle_offloads(skb, !!(tunnel->parms.o_flags&TUNNEL_CSUM));
+ if (IS_ERR(skb))
+ goto out;
+
__gre_xmit(skb, dev, tnl_params, skb->protocol);
return NETDEV_TX_OK;
copied = 0;
while (iov_iter_count(to) && copied < len) {
- to_copy = min(iov_iter_count(to), sg->length - vec_off);
+ to_copy = min_t(unsigned long, iov_iter_count(to),
+ sg->length - vec_off);
to_copy = min_t(unsigned long, to_copy, len - copied);
rds_stats_add(s_copy_to_user, to_copy);