Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --- a/drivers/net/ethernet/lantiq_xrx200.c 2019-08-13 05:00:34.508512839 +0200
- +++ b/drivers/net/ethernet/lantiq_xrx200.c 2019-08-12 05:24:46.769583694 +0200
- @@ -36,16 +36,20 @@
- #include "lantiq_pce.h"
- #include "lantiq_xrx200_sw.h"
- -#define SW_POLLING
- -#define SW_ROUTING
- +#define SW_POLLING //polls phy
- +#define SW_ROUTING //adds vlan field
- -#ifdef SW_ROUTING
- -#define XRX200_MAX_DEV 2
- -#else
- -#define XRX200_MAX_DEV 1
- -#endif
- +/* set number of TX queues: 1-2 */
- +#define MAX_TX_RINGS 2
- +
- +/* set number of RX queues: 1 */
- +#define MAX_RX_RINGS 1
- +
- +/* set number of TX queues: 1-2 */
- +#define MAX_TX_QUEUES 2
- #define XRX200_MAX_VLAN 64
- +
- #define XRX200_PCE_ACTVLAN_IDX 0x01
- #define XRX200_PCE_VLANMAP_IDX 0x02
- @@ -54,7 +58,8 @@
- #define XRX200_HEADROOM 4
- -#define XRX200_TX_TIMEOUT (10 * HZ)
- +//TODO fine tune
- +#define XRX200_TX_TIMEOUT (20 * HZ)
- /* port type */
- #define XRX200_PORT_TYPE_PHY 1
- @@ -62,12 +67,14 @@
- /* DMA */
- #define XRX200_DMA_DATA_LEN 0x600
- +#define XRX200_DMA_TX_ALIGN (32 - 1)
- +
- +//TODO in devicetree?
- #define XRX200_DMA_IRQ INT_NUM_IM2_IRL0
- #define XRX200_DMA_RX 0
- #define XRX200_DMA_TX 1
- #define XRX200_DMA_TX_2 3
- -#define XRX200_DMA_IS_TX(x) (x%2)
- -#define XRX200_DMA_IS_RX(x) (!XRX200_DMA_IS_TX(x))
- +// #define XRX200_DMA_TX_3 5
- /* fetch / store dma */
- #define FDMA_PCTRL0 0x2A00
- @@ -188,12 +195,142 @@
- #define MDIO_DEVAD_NONE (-1)
- #define ADVERTIZE_MPD (1 << 10)
- +//dev_set_drvdata
- +//https://elixir.bootlin.com/linux/v5.1-rc5/source/include/linux/device.h#L1136
- +//SET_NETDEV_DEV
- +//https://elixir.bootlin.com/linux/v5.1-rc5/source/include/linux/netdevice.h#L2208
- +
- +
- +// TODO interesting: save the structure at the begin of the skb - free alloc and free
- +/* this is used in DMA ring to match skb during cleanup */
- +struct xrx200_tx_skb {
- + /* skb in use reference */
- + struct sk_buff *skb;
- +
- + /* tx queue reference for TX housekeeping */
- + struct xrx200_tx_queue *txq;
- +
- + /* saved dma address for unmap */
- + dma_addr_t addr;
- +
- + /* saved length for unmap, max 4096 */
- + unsigned short size;
- +};
- +
- +
- +struct xrx200_rx_skb {
- + /* skb in use reference */
- + struct sk_buff *skb;
- +
- + /* saved dma address for unmap */
- + dma_addr_t addr;
- +
- + /* saved length for unmap, max 4096 */
- +// unsigned short size;
- +};
- +
- +
- +//mapped exactly to one ring
- +struct xrx200_tx_queue {
- + //only one writer must be possible!!
- + struct xrx200_tx_skb *skb_list; //up to ring sized number of skbs
- +
- + //can overflow?, scheduling
- + unsigned int head; //+1 when enqueued new packet into ring
- + unsigned int tail; //+1 when cleaned
- +
- + unsigned int num; //queue ring size
- +
- + struct u64_stats_sync syncp;
- + __u64 tx_packets;
- + __u64 tx_bytes;
- + __u64 tx_errors;
- + __u64 tx_dropped;
- +
- + //associated netdev queue
- + struct netdev_queue *nqueue;
- +
- + //for the TX queue list for TX ring
- + struct list_head queue; //TODO rename?
- +
- + struct xrx200_tx_ring *ring; //associated ring
- +};
- +
- +
- +struct xrx200_tx_ring {
- + struct napi_struct napi;
- +
- + /* ring buffer tail pointer */
- + unsigned int free;
- + // ____cacheline_aligned_in_smp;
- +
- + /* user side ring for list pointers to xrx200 skb buffer */
- + //NOTICE array could be directly there, it would mean:
- + // ring locking or
- + // (MAX_SKB_FRAGS+1)*sizeof(struct xrx200_skb) bytes in local variables
- + // (MAX_SKB_FRAGS+1)*sizeof(struct xrx200_skb) memcpy'd bytes
- + struct xrx200_tx_skb **skb_list_ptr;
- +
- + /* settings of this DMA ring */
- + struct ltq_dma_channel dma;
- +
- + /* number of ring members */
- + //TODO this should be adjustable and in ltq_dma_channel
- + int num;
- +
- + struct xrx200_priv *priv;
- +
- + /* sharing the ring between multiple queues */
- + spinlock_t lock;
- +
- + /* list of assigned TX queues, for IRQ */
- + struct list_head queues;
- +};
- +
- +
- +//TODO is priv required in both queue and ring? probably just ring?
- +struct xrx200_rx_queue {
- + /* netdev stats */
- + struct u64_stats_sync syncp;
- + __u64 rx_packets;
- + __u64 rx_bytes;
- + __u64 rx_dropped;
- +
- + /* link back to priv */
- + struct xrx200_priv *priv;
- +
- + /* associated DMA ring */
- + struct xrx200_rx_ring *ring;
- +};
- +
- +
- +struct xrx200_rx_ring {
- + /* one napi for ring */
- + struct napi_struct napi;
- +
- + /* associated DMA descriptors */
- + struct ltq_dma_channel dma;
- +
- + /* link back to priv */
- + struct xrx200_priv *priv;
- +
- + //TODO these two should be inside ltq_dma_channel
- + /* additional data per DMA descriptor */
- + struct xrx200_rx_skb *skb_list;
- +
- + /* number of descriptors */
- + int num;
- +};
- +
- +
- struct xrx200_port {
- u8 num;
- u8 phy_addr;
- u16 flags;
- phy_interface_t phy_if;
- + struct list_head port;
- +
- int link;
- int gpio;
- enum of_gpio_flags gpio_flags;
- @@ -202,53 +339,86 @@
- struct device_node *phy_node;
- };
- -struct xrx200_chan {
- - int idx;
- - int refcount;
- - int tx_free;
- - struct net_device dummy_dev;
- - struct net_device *devs[XRX200_MAX_DEV];
- +#define IF_TYPE_SWITCH 0
- +#define IF_TYPE_WAN 1
- - struct tasklet_struct tasklet;
- - struct napi_struct napi;
- - struct ltq_dma_channel dma;
- - struct sk_buff *skb[LTQ_DESC_NUM];
- +//TODO sort by sizes at the end
- +struct xrx200_iface {
- + /* associated netdev */
- + struct net_device *net_dev; //TODO zero alloc, pak se da iterovat?
- - spinlock_t lock;
- + /* TX queue, sw frontend for DMA ring */
- + struct xrx200_tx_queue *txq;
- +
- + /* number of txq members */
- + unsigned int num_tx_queues;
- +
- + /* RX queue, sw frontend for shared DMA ring */
- + /* NOTICE hardcoded 1 queue, because only 1 RX ring */
- + struct xrx200_rx_queue *rxq;
- +
- + /* interface's MAC address */
- + unsigned char mac[6];
- +
- + /* link to private */
- + //TODO better way?
- + struct xrx200_priv *priv;
- +
- + /* interface list member, for priv*/
- + struct list_head iface;
- +
- + /* head for port list */
- + //TODO this is logical hierarchy, but everybody uses for each iface/for each port
- + struct list_head ports;
- +
- + /* the interface is switch/wan type */
- + //TODO maybe enum?
- + unsigned int iftype;
- +
- + /* for interface timeouts */
- + struct u64_stats_sync syncp;
- + __u64 tx_errors;
- };
- -struct xrx200_hw {
- +
- +struct xrx200_priv {
- + /* for NAPI polling */
- + struct net_device dummy_net;
- +
- + /* hardware DMA ring, 2 channels for TX, FIXME if you have TRM */
- + struct xrx200_tx_ring tx[MAX_TX_RINGS];
- +
- + /* hardware DMA ring, 1 channel for RX, FIXME if you have TRM */
- + struct xrx200_rx_ring rx[MAX_RX_RINGS];
- +
- + /* head for interfaces list */
- + struct list_head ifaces;
- +
- struct clk *clk;
- - struct mii_bus *mii_bus;
- - struct xrx200_chan chan[XRX200_MAX_DMA];
- - u16 vlan_vid[XRX200_MAX_VLAN];
- - u16 vlan_port_map[XRX200_MAX_VLAN];
- + struct device *dev;
- - struct net_device *devs[XRX200_MAX_DEV];
- - int num_devs;
- + /* default portmap */
- + //TODO only switch affected? maybe put into iface
- + unsigned short d_port_map;
- - int port_map[XRX200_MAX_PORT];
- + //TODO seems wan map can be only at MII-1
- + /* wan port map, maybe equivalent to d_port_map? */
- unsigned short wan_map;
- - struct switch_dev swdev;
- -};
- + u16 vlan_vid[XRX200_MAX_VLAN];
- + u16 vlan_port_map[XRX200_MAX_VLAN];
- -struct xrx200_priv {
- - struct net_device_stats stats;
- - int id;
- + /* RX: MII port to interface mapping */
- + struct xrx200_iface *port_map[XRX200_MAX_PORT];
- - struct xrx200_port port[XRX200_MAX_PORT];
- - int num_port;
- - bool wan;
- - bool sw;
- - unsigned short port_map;
- - unsigned char mac[6];
- + struct mii_bus *mii_bus;
- - struct xrx200_hw *hw;
- + struct switch_dev swdev;
- };
- +
- static __iomem void *xrx200_switch_membase;
- static __iomem void *xrx200_mii_membase;
- static __iomem void *xrx200_mdio_membase;
- @@ -470,14 +640,14 @@
- }
- // swconfig interface
- -static void xrx200_hw_init(struct xrx200_hw *hw);
- +static void xrx200_hw_init(struct xrx200_priv *priv);
- // global
- static int xrx200sw_reset_switch(struct switch_dev *dev)
- {
- - struct xrx200_hw *hw = container_of(dev, struct xrx200_hw, swdev);
- + struct xrx200_priv *priv = container_of(dev, struct xrx200_priv, swdev);
- - xrx200_hw_init(hw);
- + xrx200_hw_init(priv);
- return 0;
- }
- @@ -523,7 +693,7 @@
- static int xrx200sw_set_vlan_vid(struct switch_dev *dev, const struct switch_attr *attr,
- struct switch_val *val)
- {
- - struct xrx200_hw *hw = container_of(dev, struct xrx200_hw, swdev);
- + struct xrx200_priv *priv = container_of(dev, struct xrx200_priv, swdev);
- int i;
- struct xrx200_pce_table_entry tev;
- struct xrx200_pce_table_entry tem;
- @@ -538,7 +708,7 @@
- return -EINVAL;
- }
- - hw->vlan_vid[val->port_vlan] = val->value.i;
- + priv->vlan_vid[val->port_vlan] = val->value.i;
- tev.index = val->port_vlan;
- xrx200_pce_table_entry_read(&tev);
- @@ -571,7 +741,7 @@
- static int xrx200sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val)
- {
- - struct xrx200_hw *hw = container_of(dev, struct xrx200_hw, swdev);
- + struct xrx200_priv *priv = container_of(dev, struct xrx200_priv, swdev);
- int i, portmap, tagmap, untagged;
- struct xrx200_pce_table_entry tem;
- @@ -624,7 +794,7 @@
- ltq_switch_w32_mask(0, portmap, PCE_PMAP2);
- ltq_switch_w32_mask(0, portmap, PCE_PMAP3);
- - hw->vlan_port_map[val->port_vlan] = portmap;
- + priv->vlan_port_map[val->port_vlan] = portmap;
- xrx200sw_fixup_pvids();
- @@ -722,8 +892,8 @@
- link->duplex = xrx200sw_read_x(XRX200_MAC_PSTAT_FDUP, port);
- - link->rx_flow = !!(xrx200sw_read_x(XRX200_MAC_CTRL_0_FCON, port) && 0x0010);
- - link->tx_flow = !!(xrx200sw_read_x(XRX200_MAC_CTRL_0_FCON, port) && 0x0020);
- + link->rx_flow = !!(xrx200sw_read_x(XRX200_MAC_CTRL_0_FCON, port) & 0x0010);
- + link->tx_flow = !!(xrx200sw_read_x(XRX200_MAC_CTRL_0_FCON, port) & 0x0020);
- link->aneg = !(xrx200sw_read_x(XRX200_MAC_CTRL_0_FCON, port));
- link->speed = SWITCH_PORT_SPEED_10;
- @@ -834,254 +1004,510 @@
- // .get_port_stats = xrx200sw_get_port_stats, //TODO
- };
- -static int xrx200sw_init(struct xrx200_hw *hw)
- +static int xrx200sw_init(struct xrx200_iface *iface)
- {
- - int netdev_num;
- - for (netdev_num = 0; netdev_num < hw->num_devs; netdev_num++)
- - {
- - struct switch_dev *swdev;
- - struct net_device *dev = hw->devs[netdev_num];
- - struct xrx200_priv *priv = netdev_priv(dev);
- - if (!priv->sw)
- - continue;
- + struct switch_dev *swdev;
- +
- + //TODO is it possible to have working eth without switch? (only wan?)
- + //TODO put into interface init under switch block
- +
- + swdev = &iface->priv->swdev;
- - swdev = &hw->swdev;
- + swdev->name = "Lantiq XRX200 Switch";
- + swdev->vlans = XRX200_MAX_VLAN;
- + swdev->ports = XRX200_MAX_PORT;
- + swdev->cpu_port = 6;
- + swdev->ops = &xrx200sw_ops;
- - swdev->name = "Lantiq XRX200 Switch";
- - swdev->vlans = XRX200_MAX_VLAN;
- - swdev->ports = XRX200_MAX_PORT;
- - swdev->cpu_port = 6;
- - swdev->ops = &xrx200sw_ops;
- + //TODO there should be retval?
- + return register_switch(swdev, iface->net_dev);
- +}
- +
- +/* drop all the packets from the DMA ring */
- +static void xrx200_flush_rx(struct xrx200_rx_ring *ring)
- +{
- + int i;
- +
- + for (i = 0; i < ring->num; i++) {
- + struct ltq_dma_desc *desc = &ring->dma.desc_base[ring->dma.desc];
- +
- + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) != LTQ_DMA_C)
- + break;
- +
- + desc->ctl = LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
- + XRX200_DMA_DATA_LEN;
- - register_switch(swdev, dev);
- - return 0; // enough switches
- + ring->dma.desc = (ring->dma.desc + 1) % ring->num;
- }
- - return 0;
- }
- +
- static int xrx200_open(struct net_device *dev)
- {
- - struct xrx200_priv *priv = netdev_priv(dev);
- + struct xrx200_iface *iface = netdev_priv(dev);
- + struct list_head *pos;
- int i;
- - for (i = 0; i < XRX200_MAX_DMA; i++) {
- - if (!priv->hw->chan[i].dma.irq)
- - continue;
- - spin_lock_bh(&priv->hw->chan[i].lock);
- - if (!priv->hw->chan[i].refcount) {
- - if (XRX200_DMA_IS_RX(i))
- - napi_enable(&priv->hw->chan[i].napi);
- - ltq_dma_open(&priv->hw->chan[i].dma);
- - }
- - priv->hw->chan[i].refcount++;
- - spin_unlock_bh(&priv->hw->chan[i].lock);
- - }
- - for (i = 0; i < priv->num_port; i++)
- - if (priv->port[i].phydev)
- - phy_start(priv->port[i].phydev);
- - netif_wake_queue(dev);
- + for (i = 0; i < iface->num_tx_queues; i++) {
- + //TODO must be locked
- +
- + napi_enable(&iface->txq[i].ring->napi);
- + ltq_dma_open(&iface->txq[i].ring->dma);
- + ltq_dma_enable_irq(&iface->txq[i].ring->dma);
- + }
- +
- + //TODO must be locked, tx_open?
- + napi_enable(&iface->rxq[0].ring->napi);
- + ltq_dma_open(&iface->rxq[0].ring->dma);
- +
- + /* The boot loader does not always deactivate the receiving of frames
- + * on the ports and then some packets queue up in the PPE buffers.
- + * They already passed the PMAC so they do not have the tags
- + * configured here. Read the these packets here and drop them.
- + * The HW should have written them into memory after 10us
- + */
- + usleep_range(20, 40);
- + xrx200_flush_rx(iface->rxq[0].ring);
- +
- + ltq_dma_enable_irq(&iface->rxq[0].ring->dma);
- +
- + list_for_each(pos, &iface->ports) {
- + struct xrx200_port *port = list_entry(pos,
- + struct xrx200_port,
- + port);
- + if (port->phydev)
- + phy_start(port->phydev);
- + }
- +
- + netif_tx_wake_all_queues(dev);
- return 0;
- }
- static int xrx200_close(struct net_device *dev)
- {
- - struct xrx200_priv *priv = netdev_priv(dev);
- + struct xrx200_iface *iface = netdev_priv(dev);
- + struct list_head *pos;
- int i;
- - netif_stop_queue(dev);
- + netif_tx_stop_all_queues(dev);
- - for (i = 0; i < priv->num_port; i++)
- - if (priv->port[i].phydev)
- - phy_stop(priv->port[i].phydev);
- + list_for_each(pos, &iface->ports) {
- + struct xrx200_port *port = list_entry(pos,
- + struct xrx200_port,
- + port);
- + if (port->phydev)
- + phy_stop(port->phydev);
- + }
- - for (i = 0; i < XRX200_MAX_DMA; i++) {
- - if (!priv->hw->chan[i].dma.irq)
- - continue;
- + napi_disable(&iface->rxq[0].ring->napi);
- + ltq_dma_close(&iface->rxq[0].ring->dma);
- - priv->hw->chan[i].refcount--;
- - if (!priv->hw->chan[i].refcount) {
- - if (XRX200_DMA_IS_RX(i))
- - napi_disable(&priv->hw->chan[i].napi);
- - spin_lock_bh(&priv->hw->chan[i].lock);
- - ltq_dma_close(&priv->hw->chan[XRX200_DMA_RX].dma);
- - spin_unlock_bh(&priv->hw->chan[i].lock);
- - }
- + for (i = 0; i < iface->num_tx_queues; i++) {
- + napi_disable(&iface->txq[i].ring->napi);
- + ltq_dma_close(&iface->txq[i].ring->dma);
- }
- return 0;
- }
- -static int xrx200_alloc_skb(struct xrx200_chan *ch)
- +//TODO maybe change priv to ring, alloc to RX?
- +static int xrx200_alloc_skb(struct xrx200_priv *priv,
- + struct ltq_dma_channel *dma,
- + struct xrx200_rx_skb *dma_skb)
- {
- -#define DMA_PAD (NET_IP_ALIGN + NET_SKB_PAD)
- - ch->skb[ch->dma.desc] = dev_alloc_skb(XRX200_DMA_DATA_LEN + DMA_PAD);
- - if (!ch->skb[ch->dma.desc])
- + struct ltq_dma_desc *base = &dma->desc_base[dma->desc];
- + struct sk_buff *skb;
- +
- +//#define DMA_PAD (NET_IP_ALIGN + NET_SKB_PAD)
- +// skb = netdev_alloc_skb(priv->net_dev, XRX200_DMA_DATA_LEN + DMA_PAD);
- +
- + skb = napi_alloc_skb(&priv->rx[0].napi, XRX200_DMA_DATA_LEN);
- +
- + //TODO fix fail path
- + if (unlikely(!skb)) {
- + /* leave the old skb if not enough memory */
- goto skip;
- + }
- +
- + if (likely(dma_skb->addr)) {
- + dma_unmap_single(priv->dev, dma_skb->addr,
- + XRX200_DMA_DATA_LEN, DMA_FROM_DEVICE);
- + }
- +
- + // skb_reserve(skb, NET_SKB_PAD);
- + skb_reserve(skb, -NET_IP_ALIGN);
- +
- + base->addr = dma_skb->addr =
- + dma_map_single(priv->dev, skb->data,
- + XRX200_DMA_DATA_LEN, DMA_FROM_DEVICE);
- +
- +//TODO error path
- +// if (dma_mapping_error(&cp->pdev->dev, new_mapping)) {
- +// dev->stats.rx_dropped++;
- +// kfree_skb(new_skb);
- +// goto rx_next;
- +// }
- - skb_reserve(ch->skb[ch->dma.desc], NET_SKB_PAD);
- - ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(ch->dma.dev,
- - ch->skb[ch->dma.desc]->data, XRX200_DMA_DATA_LEN,
- - DMA_FROM_DEVICE);
- - ch->dma.desc_base[ch->dma.desc].addr =
- - CPHYSADDR(ch->skb[ch->dma.desc]->data);
- - skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN);
- +
- + skb_reserve(skb, NET_IP_ALIGN);
- +
- + dma_skb->skb = skb;
- +
- + wmb();
- skip:
- - ch->dma.desc_base[ch->dma.desc].ctl =
- - LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
- + base->ctl = LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
- XRX200_DMA_DATA_LEN;
- + dma->desc = (dma->desc + 1) % priv->rx[0].num;
- +
- return 0;
- }
- -static void xrx200_hw_receive(struct xrx200_chan *ch, int id)
- +
- +static void xrx200_hw_receive(struct xrx200_priv *priv,
- + struct xrx200_iface *iface,
- + struct ltq_dma_channel *dma,
- + struct xrx200_rx_skb *dma_skb
- + )
- {
- - struct net_device *dev = ch->devs[id];
- - struct xrx200_priv *priv = netdev_priv(dev);
- - struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
- - struct sk_buff *skb = ch->skb[ch->dma.desc];
- + struct ltq_dma_desc *desc = &dma->desc_base[dma->desc];
- + struct net_device *dev = iface->net_dev;
- + struct xrx200_rx_queue *rxq = iface->rxq;
- int len = (desc->ctl & LTQ_DMA_SIZE_MASK);
- int ret;
- + /* struct value will get overwritten by xrx200_alloc_skb */
- + struct sk_buff *filled_skb = dma_skb->skb;
- - ret = xrx200_alloc_skb(ch);
- -
- - ch->dma.desc++;
- - ch->dma.desc %= LTQ_DESC_NUM;
- + /* alloc new skb first so DMA ring can work during netif_receive_skb */
- + ret = xrx200_alloc_skb(priv, dma, dma_skb);
- if (ret) {
- netdev_err(dev,
- "failed to allocate new rx buffer\n");
- +
- + //TODO
- return;
- }
- - skb_put(skb, len);
- + /* set skb length for netdev */
- + skb_put(filled_skb, len);
- #ifdef SW_ROUTING
- - skb_pull(skb, 8);
- + /* remove special tag */
- + skb_pull(filled_skb, 8);
- #endif
- - skb->dev = dev;
- - skb->protocol = eth_type_trans(skb, dev);
- - netif_receive_skb(skb);
- - priv->stats.rx_packets++;
- - priv->stats.rx_bytes+=len;
- +
- + filled_skb->protocol = eth_type_trans(filled_skb, dev);
- +
- + //TODO redo for netif_receive_skb_list? problem is deciding overhead between netdev
- + ret = netif_receive_skb(filled_skb);
- +
- + if (likely(ret == NET_RX_SUCCESS)) {
- + u64_stats_update_begin(&rxq->syncp);
- + rxq->rx_bytes += len;
- + rxq->rx_packets++;
- + u64_stats_update_end(&rxq->syncp);
- + } else {
- +
- + u64_stats_update_begin(&rxq->syncp);
- + rxq->rx_dropped++;
- + u64_stats_update_end(&rxq->syncp);
- + }
- +
- +// info napi_gro_receive(&rxq->napi, filled_skb); too simple soc?
- +
- }
- static int xrx200_poll_rx(struct napi_struct *napi, int budget)
- {
- - struct xrx200_chan *ch = container_of(napi,
- - struct xrx200_chan, napi);
- - struct xrx200_priv *priv = netdev_priv(ch->devs[0]);
- + struct xrx200_rx_ring *ring = container_of(napi,
- + struct xrx200_rx_ring, napi);
- + struct ltq_dma_channel *dma = &ring->dma;
- + struct xrx200_priv *priv = ring->priv;
- int rx = 0;
- - int complete = 0;
- - while ((rx < budget) && !complete) {
- - struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
- - if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
- + //read the ring
- + //put skb to the correct queue
- + //(if all queues have more items than ring -> ring will have to wait)
- + //if all queues have less items than ring -> ring may get stuck
- + //TODO delete ^^
- +
- + while (rx < budget) {
- + struct ltq_dma_desc *desc = &dma->desc_base[dma->desc];
- + if (likely((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C)) {
- + struct xrx200_rx_skb *dma_skb = &ring->skb_list[dma->desc];
- +
- +//TODO TODO TODO
- +#if 0
- +#if 1
- #ifdef SW_ROUTING
- - struct sk_buff *skb = ch->skb[ch->dma.desc];
- - u8 *special_tag = (u8*)skb->data;
- - int port = (special_tag[7] >> SPPID_SHIFT) & SPPID_MASK;
- - xrx200_hw_receive(ch, priv->hw->port_map[port]);
- + const unsigned char port = (dma_skb->skb->data[7] >> SPPID_SHIFT) & SPPID_MASK;
- +#else
- +//TODO not sure if this codepath works, anyone using !SW_ROUTING here?
- + const unsigned char port = 0;
- +#endif
- +#endif
- #else
- - xrx200_hw_receive(ch, 0);
- +
- +//TODO forced interface 0, test uninialized ifaces -> NULL pointers
- +const unsigned char port = 0;
- +#endif
- +
- +
- +// TODO it could be even possible to make a single eth interface for every rj45 connector, but things like mac addresses...
- +
- +#if 0
- + {
- + int i;
- +
- +pr_info("%px %px %px %i %i %px, dump:\n",
- +dma,
- +dma_skb,
- +dma_skb->skb,
- +dma->desc,
- +port,
- +priv->port_map[port]->net_dev);
- +
- + for (i = 0; i < 16;i++) {
- + pr_cont("%02x ", dma_skb->skb->data[i]);
- + if ((i % 8) == 7)
- + pr_cont("\n");
- + }
- + pr_cont("\n");
- + }
- #endif
- +
- +//port (LAN switch/wan) is mapped on xrx200_iface
- + xrx200_hw_receive(priv, priv->port_map[port], dma,
- + dma_skb);
- rx++;
- } else {
- - complete = 1;
- + break;
- }
- }
- - if (complete || !rx) {
- - napi_complete(&ch->napi);
- - ltq_dma_enable_irq(&ch->dma);
- + //TODO
- + if (rx < budget) {
- + if (napi_complete_done(napi, rx)) {
- +//can an unacked irq event wait here now?
- + ltq_dma_enable_irq(dma);
- + }
- }
- return rx;
- }
- -static void xrx200_tx_housekeeping(unsigned long ptr)
- -{
- - struct xrx200_chan *ch = (struct xrx200_chan *) ptr;
- - int pkts = 0;
- - int i;
- +//TODO is this macro valid?
- +#define TX_BUFFS_AVAIL(tail, head, num) \
- + ((tail <= head) ? \
- + tail + (num - 1) - head : \
- + tail - head - 1)
- +
- +static int xrx200_tx_housekeeping(struct napi_struct *napi, int budget)
- +{
- + struct xrx200_tx_ring *ring =
- + container_of(napi, struct xrx200_tx_ring, napi);
- + // struct net_device *net_dev = txq->priv->net_dev;
- + int pkts = 0; //napi complete has int, hw will fit into usinged short
- + unsigned short size = 0;
- + unsigned int free;
- + struct xrx200_tx_queue *txq;
- + struct ltq_dma_desc *desc;
- + struct list_head *pos;
- - spin_lock_bh(&ch->lock);
- - ltq_dma_ack_irq(&ch->dma);
- - while ((ch->dma.desc_base[ch->tx_free].ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
- - struct sk_buff *skb = ch->skb[ch->tx_free];
- + free = ring->free; //read once? TODO
- - pkts++;
- - ch->skb[ch->tx_free] = NULL;
- - dev_kfree_skb(skb);
- - memset(&ch->dma.desc_base[ch->tx_free], 0,
- - sizeof(struct ltq_dma_desc));
- - ch->tx_free++;
- - ch->tx_free %= LTQ_DESC_NUM;
- +//TODO pkts vs frags, frags means fullness of ring, pkts means napi budget!
- +
- + while (likely(pkts < budget)) {
- + desc = &ring->dma.desc_base[free];
- +
- + //TODO into while condition? an additional read
- + //speed tests
- + if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
- + struct xrx200_tx_skb *dma_skb = ring->skb_list_ptr[free];
- +
- + //all frags after SOP are from the same TXQ
- + //NOTICE but frags/pkts
- +// if (desc->ctl & LTQ_DMA_SOP) {
- +// txq = skb_list_ptr[free]->txq;
- +// tail = txq->tail;
- +// }
- +
- + //TODO txq operations could be speed up, between SOP and EOP
- + // there must be the same txq
- + // also we could accumulate stats for one txq run
- +
- + txq = dma_skb->txq;
- +
- + size = dma_skb->size;
- +
- + //TODO device
- + dma_unmap_single(ring->priv->dev, dma_skb->addr,
- + (size_t) size, DMA_TO_DEVICE);
- +
- + if (desc->ctl & LTQ_DMA_EOP) {
- + //TODO there could be a local variable and update it at the end
- + //problem: mixed queues
- + u64_stats_update_begin(&txq->syncp);
- + txq->tx_packets++;
- + txq->tx_bytes += size;
- + u64_stats_update_end(&txq->syncp);
- +
- + if (likely(dma_skb->skb)) {
- + //last frag
- + dev_consume_skb_irq(dma_skb->skb);
- + dma_skb->skb = NULL; //TODO is it required?
- + pkts++;
- + } else {
- + //debug?
- + dev_warn(ring->priv->dev, "TX ring skb pointer is NULL\n");
- + }
- + } else {
- + //TODO there could be a local variable and update it at the end
- + //problem: mixed queues
- + u64_stats_update_begin(&txq->syncp);
- + txq->tx_bytes += size;
- + u64_stats_update_end(&txq->syncp);
- + }
- +
- +
- + txq->tail = (txq->tail + 1) % txq->num;
- +
- + /* erase descriptor flags */
- + desc->ctl = 0;
- +
- + free = (free + 1) % ring->num;
- + } else {
- + break;
- + }
- }
- - ltq_dma_enable_irq(&ch->dma);
- - spin_unlock_bh(&ch->lock);
- - if (!pkts)
- - return;
- + ring->free = free;
- - for (i = 0; i < XRX200_MAX_DEV && ch->devs[i]; i++)
- - netif_wake_queue(ch->devs[i]);
- -}
- + /* test which queue housekeeping should be scheduled */
- + list_for_each(pos, &ring->queues) {
- + txq = list_entry(pos, struct xrx200_tx_queue, queue);
- +
- + /* wake up queue only if there is enough space */
- + if (unlikely(TX_BUFFS_AVAIL(txq->tail, txq->head, txq->num) > (MAX_SKB_FRAGS + 1))) {
- + if (netif_tx_queue_stopped(txq->nqueue)) {
- + netif_tx_wake_queue(txq->nqueue);
- + }
- + }
- + }
- -static struct net_device_stats *xrx200_get_stats (struct net_device *dev)
- -{
- - struct xrx200_priv *priv = netdev_priv(dev);
- + if (pkts < budget) {
- + if (napi_complete_done(napi, pkts)) {
- + ltq_dma_enable_irq(&ring->dma);
- + }
- + }
- - return &priv->stats;
- + return pkts;
- }
- -static void xrx200_tx_timeout(struct net_device *dev)
- +
- +static void xrx200_tx_timeout(struct net_device *ndev)
- {
- - struct xrx200_priv *priv = netdev_priv(dev);
- + struct xrx200_iface *iface = netdev_priv(ndev);
- +
- + netdev_err(ndev, "transmit timed out!\n");
- - printk(KERN_ERR "%s: transmit timed out, disable the dma channel irq\n", dev->name);
- + u64_stats_update_begin(&iface->syncp);
- + iface->tx_errors++;
- + u64_stats_update_end(&iface->syncp);
- - priv->stats.tx_errors++;
- - netif_wake_queue(dev);
- + netif_tx_wake_all_queues(ndev);
- }
- -static int xrx200_start_xmit(struct sk_buff *skb, struct net_device *dev)
- -{
- - struct xrx200_priv *priv = netdev_priv(dev);
- - struct xrx200_chan *ch;
- - struct ltq_dma_desc *desc;
- - u32 byte_offset;
- +
- +#if 0
- +//testing "packet"
- +char test_packet[] = {
- + 0,0,0,0, //headroom
- + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc4, 0xe9, 0x84, 0x2a, 0xbd, 0x51, 0x08, 0x06, 0x00, 0x01,
- + 0x08, 0x00, 0x06, 0x04, 0x00, 0x01, 0xc4, 0xe9, 0x84, 0x2a, 0xbd, 0x51, 0x0a, 0x00, 0x00, 0x50,
- + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
- +};
- +
- +long test_counter=1;
- +
- +#endif
- +
- +//TODO netdev queues, stats per queue or netdev, is xmit exclusive
- +// struct napi_struct napi ____cacheline_aligned;
- +//https://elixir.bootlin.com/linux/v5.1-rc5/source/drivers/net/ethernet/broadcom/bcmsysport.h#L740
- +// struct ltq_etop_priv *priv = netdev_priv(dev);
- +//stats collision in housekeeping per queue/netdev/ring ?
- +//MAX_SKB_FRAGS
- +
- +static netdev_tx_t xrx200_start_xmit(struct sk_buff *skb,
- + struct net_device *dev)
- +{
- + struct xrx200_iface *iface = netdev_priv(dev);
- + struct xrx200_priv *priv = iface->priv;
- + struct xrx200_tx_queue *txq;
- + struct xrx200_tx_ring *ring;
- + unsigned int ring_head;
- + unsigned int head;
- int ret = NETDEV_TX_OK;
- int len;
- + int i;
- + u16 queue_id;
- #ifdef SW_ROUTING
- u32 special_tag = (SPID_CPU_PORT << SPID_SHIFT) | DPID_ENABLE;
- #endif
- - if(priv->id)
- - ch = &priv->hw->chan[XRX200_DMA_TX_2];
- - else
- - ch = &priv->hw->chan[XRX200_DMA_TX];
- + unsigned long flags;
- + unsigned int idx;
- - desc = &ch->dma.desc_base[ch->dma.desc];
- + //TODO will always skb queue match nqueue from txq?
- + queue_id = skb_get_queue_mapping(skb);
- + txq = &iface->txq[queue_id];
- - skb->dev = dev;
- - len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
- + if (unlikely(TX_BUFFS_AVAIL(txq->tail, txq->head, txq->num) <= (MAX_SKB_FRAGS + 1))) {
- + netif_tx_stop_queue(txq->nqueue);
- +
- + /*
- + * This is usually a bug, the code must foresee this
- + * at the end of this function
- + */
- + netdev_err(dev, "not enough space on queue %i\n", queue_id);
- +
- + return NETDEV_TX_BUSY;
- + }
- +
- + if (skb_put_padto(skb, ETH_ZLEN)) {
- + /* XXX: is this pr_err or normal/none code path? */
- + u64_stats_update_begin(&txq->syncp);
- + txq->tx_dropped++;
- + u64_stats_update_end(&txq->syncp);
- +
- + return NETDEV_TX_OK;
- + }
- +
- + //TODO is support for more than one queue per cpu per iface overkill?
- +// ring = &priv->tx[queue_id % MAX_TX_RINGS];
- + ring = txq->ring;
- #ifdef SW_ROUTING
- if (is_multicast_ether_addr(eth_hdr(skb)->h_dest)) {
- - u16 port_map = priv->port_map;
- + u16 port_map = priv->d_port_map;
- - if (priv->sw && skb->protocol == htons(ETH_P_8021Q)) {
- + if ((iface->iftype & BIT(IF_TYPE_SWITCH)) &&
- + skb->protocol == htons(ETH_P_8021Q)) {
- u16 vid;
- int i;
- port_map = 0;
- if (!__vlan_get_tag(skb, &vid)) {
- for (i = 0; i < XRX200_MAX_VLAN; i++) {
- - if (priv->hw->vlan_vid[i] != vid)
- - continue;
- - port_map = priv->hw->vlan_port_map[i];
- - break;
- + if (priv->vlan_vid[i] == vid) {
- + port_map = priv->vlan_port_map[i];
- + break;
- + }
- }
- }
- }
- @@ -1089,109 +1515,327 @@
- special_tag |= (port_map << PORT_MAP_SHIFT) |
- PORT_MAP_SEL | PORT_MAP_EN;
- }
- - if(priv->wan)
- +
- + if (iface->iftype & BIT(IF_TYPE_WAN))
- special_tag |= (1 << DPID_SHIFT);
- - if(skb_headroom(skb) < 4) {
- - struct sk_buff *tmp = skb_realloc_headroom(skb, 4);
- +
- + if (skb_headroom(skb) < XRX200_HEADROOM) {
- + struct sk_buff *tmp = skb_realloc_headroom(skb, XRX200_HEADROOM);
- dev_kfree_skb_any(skb);
- skb = tmp;
- }
- - skb_push(skb, 4);
- +
- + skb_push(skb, XRX200_HEADROOM);
- memcpy(skb->data, &special_tag, sizeof(u32));
- - len += 4;
- #endif
- - /* dma needs to start on a 16 byte aligned address */
- - byte_offset = CPHYSADDR(skb->data) % 16;
- + if (skb_shinfo(skb)->nr_frags == 0) {
- + len = skb->len;
- + } else {
- + len = skb_headlen(skb);
- + }
- +
- + head = txq->head;
- - spin_lock_bh(&ch->lock);
- - if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
- - netdev_err(dev, "tx ring full\n");
- - netif_stop_queue(dev);
- - ret = NETDEV_TX_BUSY;
- + /* Map to DMA first, we cannot fail after ring allocation */
- +
- + /* map basic fragment of packet */
- + // TODO,weird : etop uses virt_to_phys, but here it would not work
- + txq->skb_list[head].addr = dma_map_single(priv->dev, skb->data, len, DMA_TO_DEVICE);
- + if (unlikely(dma_mapping_error(priv->dev, txq->skb_list[head].addr))) {
- + netdev_err(dev, "DMA mapping failed for skb\n");
- +
- + dev_kfree_skb(skb);
- +
- + u64_stats_update_begin(&txq->syncp);
- + txq->tx_dropped++;
- + txq->tx_errors++;
- + u64_stats_update_end(&txq->syncp);
- +
- + ret = NETDEV_TX_OK;
- goto out;
- }
- - ch->skb[ch->dma.desc] = skb;
- + txq->skb_list[head].size = len;
- +
- + /* map rest of fragments */
- + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- + const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- +
- + idx = (head + i + 1) % txq->num;
- +
- + len = skb_frag_size(frag);
- +
- + txq->skb_list[idx].addr = dma_map_single(priv->dev,
- + skb_frag_address(frag),
- + len, DMA_TO_DEVICE);
- +
- + if (unlikely(dma_mapping_error(priv->dev, txq->skb_list[idx].addr))) {
- + netdev_err(dev, "DMA mapping for fragment #%i failed\n", i);
- +
- + i--;
- +
- + for (; i >= 0; i--) {
- + idx = (head + i + 1) % txq->num;
- + dma_unmap_single(priv->dev, txq->skb_list[idx].addr,
- + txq->skb_list[idx].size,
- + DMA_TO_DEVICE);
- + }
- +
- + dma_unmap_single(priv->dev, txq->skb_list[head].addr,
- + txq->skb_list[head].size, DMA_TO_DEVICE);
- +
- + dev_kfree_skb(skb);
- +
- + u64_stats_update_begin(&txq->syncp);
- + txq->tx_dropped++;
- + txq->tx_errors++;
- + u64_stats_update_end(&txq->syncp);
- +
- + ret = NETDEV_TX_OK;
- + goto out;
- + }
- +
- + txq->skb_list[idx].size = len;
- + }
- +
- + /* we need to lock from other queues using the same ring */
- + spin_lock_irqsave(&ring->lock, flags);
- +
- + ring_head = ring->dma.desc;
- +
- + /* check if there is free space in DMA ring */
- + if (unlikely(TX_BUFFS_AVAIL(ring->free, ring_head, ring->num) <= (MAX_SKB_FRAGS + 1))) {
- + spin_unlock_irqrestore(&ring->lock, flags);
- +
- + netif_tx_stop_queue(txq->nqueue);
- + netdev_err(dev, "not enough space on ring %i\n", queue_id);
- +
- + for (i = skb_shinfo(skb)->nr_frags; i >= 0; i--) {
- + idx = (head + i + 1) % txq->num;
- +
- + dma_unmap_single(priv->dev, txq->skb_list[idx].addr,
- + txq->skb_list[idx].size, DMA_TO_DEVICE);
- + }
- +
- + dma_unmap_single(priv->dev, txq->skb_list[idx].addr,
- + txq->skb_list[idx].size, DMA_TO_DEVICE);
- +
- + return NETDEV_TX_BUSY;
- + }
- +
- + /* Allocate the space in DMA ring, we cannot fail, ring shared */
- + ring->dma.desc = (ring_head + skb_shinfo(skb)->nr_frags + 1) % ring->num;
- +
- + spin_unlock_irqrestore(&ring->lock, flags);
- +
- + /* Allocate the space for queue ring */
- + txq->head = (head + skb_shinfo(skb)->nr_frags + 1) % txq->num;
- +
- + /* fill all descriptors from queue ring to DMA ring */
- + for (i = 0; i < skb_shinfo(skb)->nr_frags + 1; i++) {
- + struct ltq_dma_desc *desc;
- + struct xrx200_tx_skb *skb_list;
- + unsigned int ring_idx = (ring_head + i) % ring->num;
- +
- + desc = &ring->dma.desc_base[ring_idx];
- + skb_list = &txq->skb_list[(head + i) % txq->num];
- - netif_trans_update(dev);
- + skb_list->skb = skb;
- + skb_list->txq = txq;
- - desc->addr = ((unsigned int) dma_map_single(ch->dma.dev, skb->data, len,
- - DMA_TO_DEVICE)) - byte_offset;
- + ring->skb_list_ptr[ring_idx] = skb_list;
- +
- + desc->addr = (skb_list->addr & 0x1fffffe0) | (1<<31);
- +
- + if (i == 0) {
- + /* first frag of packet needs SOP, cannot have OWN yet */
- + desc->ctl = LTQ_DMA_SOP |
- + LTQ_DMA_TX_OFFSET(skb_list->addr & XRX200_DMA_TX_ALIGN) |
- + (skb_list->size & LTQ_DMA_SIZE_MASK);
- + } else {
- + /* other fragments of a packet can have OWN */
- + desc->ctl = LTQ_DMA_OWN |
- + LTQ_DMA_TX_OFFSET(skb_list->addr & XRX200_DMA_TX_ALIGN) |
- + (skb_list->size & LTQ_DMA_SIZE_MASK);
- + }
- +
- + /* the last fragment needs EOP */
- + if (i == skb_shinfo(skb)->nr_frags)
- + desc->ctl |= LTQ_DMA_EOP;
- + }
- +
- + /* before changing ownership to HW, everything must be written to RAM */
- wmb();
- - desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
- - LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
- - ch->dma.desc++;
- - ch->dma.desc %= LTQ_DESC_NUM;
- - if (ch->dma.desc == ch->tx_free)
- - netif_stop_queue(dev);
- + /* Start TX DMA, set OWN for the first fragment */
- + ring->dma.desc_base[ring_head].ctl |= LTQ_DMA_OWN;
- - priv->stats.tx_packets++;
- - priv->stats.tx_bytes+=len;
- + /* stop the queue until there is enough space in both rings */
- + if (unlikely((TX_BUFFS_AVAIL(ring->free, ring->dma.desc, ring->num) <= (MAX_SKB_FRAGS + 1)) ||
- + (TX_BUFFS_AVAIL(txq->tail, txq->head, txq->num) <= (MAX_SKB_FRAGS + 1)))) {
- + netif_tx_stop_queue(txq->nqueue);
- + }
- -out:
- - spin_unlock_bh(&ch->lock);
- + skb_tx_timestamp(skb);
- +out:
- return ret;
- }
- -static irqreturn_t xrx200_dma_irq(int irq, void *priv)
- +//NOTICE irq events must be as low as possible (big overhead on slow CPU)
- +static irqreturn_t xrx200_tx_dma_irq(int irq, void *ptr)
- {
- - struct xrx200_hw *hw = priv;
- - int chnr = irq - XRX200_DMA_IRQ;
- - struct xrx200_chan *ch = &hw->chan[chnr];
- + struct xrx200_tx_ring *ring = ptr;
- - ltq_dma_disable_irq(&ch->dma);
- - ltq_dma_ack_irq(&ch->dma);
- + ltq_dma_disable_irq(&ring->dma);
- + ltq_dma_ack_irq(&ring->dma);
- - if (chnr % 2)
- - tasklet_schedule(&ch->tasklet);
- - else
- - napi_schedule(&ch->napi);
- + napi_schedule_irqoff(&ring->napi);
- + return IRQ_HANDLED;
- +}
- +
- +//NOTICE it would be nice to have IRQ events in rx as low as possible too, how?
- +static irqreturn_t xrx200_rx_dma_irq(int irq, void *ptr)
- +{
- + struct xrx200_rx_ring *ring = ptr;
- +
- + ltq_dma_disable_irq(&ring->dma);
- + ltq_dma_ack_irq(&ring->dma);
- +
- + napi_schedule_irqoff(&ring->napi);
- return IRQ_HANDLED;
- }
- -static int xrx200_dma_init(struct device *dev, struct xrx200_hw *hw)
- +
- +static int xrx200_dma_init(struct xrx200_priv *priv)
- {
- - int i, err = 0;
- + int i;
- + int ret;
- + char *irq_name;
- ltq_dma_init_port(DMA_PORT_ETOP);
- - for (i = 0; i < 8 && !err; i++) {
- - int irq = XRX200_DMA_IRQ + i;
- - struct xrx200_chan *ch = &hw->chan[i];
- -
- - spin_lock_init(&ch->lock);
- -
- - ch->idx = ch->dma.nr = i;
- - ch->dma.dev = dev;
- -
- - if (i == XRX200_DMA_TX) {
- - ltq_dma_alloc_tx(&ch->dma);
- - err = request_irq(irq, xrx200_dma_irq, 0, "vrx200_tx", hw);
- - } else if (i == XRX200_DMA_TX_2) {
- - ltq_dma_alloc_tx(&ch->dma);
- - err = request_irq(irq, xrx200_dma_irq, 0, "vrx200_tx_2", hw);
- - } else if (i == XRX200_DMA_RX) {
- - ltq_dma_alloc_rx(&ch->dma);
- - for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM;
- - ch->dma.desc++)
- - if (xrx200_alloc_skb(ch))
- - err = -ENOMEM;
- - ch->dma.desc = 0;
- - err = request_irq(irq, xrx200_dma_irq, 0, "vrx200_rx", hw);
- - } else
- - continue;
- + //TODO external definitions?
- + priv->rx[0].dma.irq = XRX200_DMA_IRQ + XRX200_DMA_RX;
- + priv->rx[0].dma.nr = XRX200_DMA_RX;
- +
- + //TODO into ltq_dma_channel?
- + priv->rx[0].num = LTQ_DESC_NUM;
- +
- + for (i = 0; i < MAX_RX_RINGS; i++) {
- + struct xrx200_rx_ring *ring = &priv->rx[i];
- + int idx;
- +
- + ring->dma.dev = priv->dev;
- + ring->priv = priv;
- +
- + ltq_dma_alloc_rx(&ring->dma); //TODO add ring num
- +
- + //TODO into ltq_dma_channel?
- + ring->skb_list = devm_kzalloc(priv->dev, ring->num *
- + sizeof(struct xrx200_rx_skb), GFP_KERNEL);
- +
- + //TODO is null
- +
- + /* NOTICE this will be incremented in xrx200_alloc_skb */
- + ring->dma.desc = 0;
- +
- + for (idx = 0; idx < ring->num; idx++) {
- + ret = xrx200_alloc_skb(priv, &ring->dma,
- + &ring->skb_list[idx]);
- + if (ret)
- + #warning "TODO ERROR PATHS"
- + goto rx_free;
- + }
- +
- + /* NOTICE reset "head" after xrx200_alloc_skb */
- + ring->dma.desc = 0;
- +
- + irq_name = devm_kasprintf(priv->dev, GFP_KERNEL, "xrx200-net rx%d", i);
- + //TODO null
- +
- + ret = devm_request_irq(priv->dev, ring->dma.irq, xrx200_rx_dma_irq, 0,
- + irq_name, ring);
- + if (ret) {
- + dev_err(priv->dev, "failed to request RX irq %d\n",
- + ring->dma.irq);
- + goto rx_ring_free;
- + }
- - if (!err)
- - ch->dma.irq = irq;
- - else
- - pr_err("net-xrx200: failed to request irq %d\n", irq);
- }
- - return err;
- + //TODO TX rings vs cpuid nr_cpu_ids
- +
- + //TODO this is HACK, devicetree? or at least array
- + priv->tx[0].dma.irq = XRX200_DMA_IRQ + XRX200_DMA_TX;
- + priv->tx[0].dma.nr = XRX200_DMA_TX;
- + priv->tx[0].num = LTQ_DESC_NUM;
- + priv->tx[1].dma.irq = XRX200_DMA_IRQ + XRX200_DMA_TX_2;
- + priv->tx[1].dma.nr = XRX200_DMA_TX_2;
- + priv->tx[1].num = LTQ_DESC_NUM;
- +
- +
- + for (i = 0; i < MAX_TX_RINGS; i++) {
- + struct xrx200_tx_ring *ring = &priv->tx[i];
- + ring->dma.dev = priv->dev;
- +
- + ring->priv = priv;
- +
- + spin_lock_init(&ring->lock);
- +
- +
- + ltq_dma_alloc_tx(&ring->dma);
- +
- + ring->free = 0;
- +
- +
- + INIT_LIST_HEAD(&ring->queues);
- +
- + /* array of pointers */
- + ring->skb_list_ptr = devm_kzalloc(priv->dev, ring->num *
- + sizeof(struct xrx200_tx_skb *), GFP_KERNEL);
- + //TODO err path
- +
- + irq_name = devm_kasprintf(priv->dev, GFP_KERNEL, "xrx200-net tx%d", i);
- +
- + //TODO err path
- +
- + ret = devm_request_irq(priv->dev, ring->dma.irq, xrx200_tx_dma_irq, 0,
- + irq_name, ring);
- +
- + if (ret) {
- + dev_err(priv->dev, "failed to request TX irq %d\n",
- + ring->dma.irq);
- +
- + for (; i >= 0; i--) {
- + ltq_dma_free(&ring->dma);
- + }
- +
- + goto rx_ring_free;
- + }
- + }
- +
- + return ret;
- +
- +rx_ring_free:
- +
- +
- +rx_free:
- +return ret;
- +//TODO redo
- +#if 0
- + /* free the allocated RX ring */
- + for (i = 0; i < LTQ_DESC_NUM; i++) {
- + if (rxq->dma_skb[i].skb)
- + dev_kfree_skb_any(rxq->dma_skb[i].skb);
- + }
- +
- +rx_free:
- + ltq_dma_free(&rxq->dma);
- + return ret;
- +#endif
- }
- #ifdef SW_POLLING
- @@ -1249,19 +1893,22 @@
- static void xrx200_mdio_link(struct net_device *dev)
- {
- - struct xrx200_priv *priv = netdev_priv(dev);
- - int i;
- + struct xrx200_iface *iface = netdev_priv(dev);
- + struct list_head *pos;
- +
- + list_for_each(pos, &iface->ports) {
- + struct xrx200_port *port = list_entry(pos, struct xrx200_port,
- + port);
- - for (i = 0; i < priv->num_port; i++) {
- - if (!priv->port[i].phydev)
- + if (!port->phydev)
- continue;
- - if (priv->port[i].link != priv->port[i].phydev->link) {
- - xrx200_gmac_update(&priv->port[i]);
- - priv->port[i].link = priv->port[i].phydev->link;
- + if (port->link != port->phydev->link) {
- + xrx200_gmac_update(port);
- + port->link = port->phydev->link;
- netdev_info(dev, "port %d %s link\n",
- - priv->port[i].num,
- - (priv->port[i].link)?("got"):("lost"));
- + port->num,
- + (port->link)?("got"):("lost"));
- }
- }
- }
- @@ -1311,14 +1958,16 @@
- static int xrx200_phy_has_link(struct net_device *dev)
- {
- - struct xrx200_priv *priv = netdev_priv(dev);
- - int i;
- + struct xrx200_iface *iface = netdev_priv(dev);
- + struct list_head *pos;
- - for (i = 0; i < priv->num_port; i++) {
- - if (!priv->port[i].phydev)
- + list_for_each(pos, &iface->ports) {
- + struct xrx200_port *port = list_entry(pos, struct xrx200_port,
- + port);
- + if (!port->phydev)
- continue;
- - if (priv->port[i].phydev->link)
- + if (port->phydev->link)
- return 1;
- }
- @@ -1341,11 +1990,14 @@
- static int xrx200_mdio_probe(struct net_device *dev, struct xrx200_port *port)
- {
- - struct xrx200_priv *priv = netdev_priv(dev);
- + struct xrx200_iface *iface = netdev_priv(dev);
- + struct xrx200_priv *priv = iface->priv;
- struct phy_device *phydev = NULL;
- +#ifdef SW_POLLING
- unsigned val;
- +#endif
- - phydev = mdiobus_get_phy(priv->hw->mii_bus, port->phy_addr);
- + phydev = mdiobus_get_phy(priv->mii_bus, port->phy_addr);
- if (!phydev) {
- netdev_err(dev, "no PHY found\n");
- @@ -1378,10 +2030,10 @@
- #ifdef SW_POLLING
- phy_read_status(phydev);
- - val = xrx200_mdio_rd(priv->hw->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000);
- + val = xrx200_mdio_rd(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000);
- val |= ADVERTIZE_MPD;
- - xrx200_mdio_wr(priv->hw->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000, val);
- - xrx200_mdio_wr(priv->hw->mii_bus, 0, 0, 0x1040);
- + xrx200_mdio_wr(priv->mii_bus, MDIO_DEVAD_NONE, MII_CTRL1000, val);
- + xrx200_mdio_wr(priv->mii_bus, 0, 0, 0x1040);
- phy_start_aneg(phydev);
- #endif
- @@ -1458,27 +2110,23 @@
- static int xrx200_init(struct net_device *dev)
- {
- - struct xrx200_priv *priv = netdev_priv(dev);
- + struct xrx200_iface *iface = netdev_priv(dev);
- + struct xrx200_priv *priv = iface->priv;
- + struct xrx200_port *port;
- struct sockaddr mac;
- - int err, i;
- -
- -#ifndef SW_POLLING
- - unsigned int reg = 0;
- -
- - /* enable auto polling */
- - for (i = 0; i < priv->num_port; i++)
- - reg |= BIT(priv->port[i].num);
- - ltq_mdio_w32(reg, MDIO_CLK_CFG0);
- - ltq_mdio_w32(MDIO1_25MHZ, MDIO_CLK_CFG1);
- -#endif
- + int err;
- + struct list_head *pos;
- /* setup each port */
- - for (i = 0; i < priv->num_port; i++)
- - xrx200_port_config(priv, &priv->port[i]);
- + list_for_each(pos, &iface->ports) {
- + port = list_entry(pos, struct xrx200_port, port);
- +
- + xrx200_port_config(priv, port);
- + }
- - memcpy(&mac.sa_data, priv->mac, ETH_ALEN);
- + memcpy(&mac.sa_data, iface->mac, ETH_ALEN);
- if (!is_valid_ether_addr(mac.sa_data)) {
- - pr_warn("net-xrx200: invalid MAC, using random\n");
- + netdev_warn(dev, "net-xrx200: invalid MAC, using random\n");
- eth_random_addr(mac.sa_data);
- dev->addr_assign_type |= NET_ADDR_RANDOM;
- }
- @@ -1487,16 +2135,20 @@
- if (err)
- goto err_netdev;
- - for (i = 0; i < priv->num_port; i++)
- - if (xrx200_mdio_probe(dev, &priv->port[i]))
- - pr_warn("xrx200-mdio: probing phy of port %d failed\n",
- - priv->port[i].num);
- + list_for_each(pos, &iface->ports) {
- + port = list_entry(pos, struct xrx200_port, port);
- +
- + if (xrx200_mdio_probe(dev, port))
- + netdev_warn(dev, "xrx200-mdio: probing phy of port %d failed\n",
- + port->num);
- + //TODO error path
- + }
- return 0;
- err_netdev:
- unregister_netdev(dev);
- - free_netdev(dev);
- + //free_netdev(dev); //devm?? TODO
- return err;
- }
- @@ -1524,19 +2176,20 @@
- ltq_switch_w32_mask(0, BIT(3), PCE_GCTRL_REG(0));
- }
- -static void xrx200_hw_init(struct xrx200_hw *hw)
- +static void xrx200_hw_init(struct xrx200_priv *priv)
- {
- int i;
- /* enable clock gate */
- - clk_enable(hw->clk);
- + clk_enable(priv->clk);
- ltq_switch_w32(1, 0);
- mdelay(100);
- ltq_switch_w32(0, 0);
- +
- /*
- - * TODO: we should really disbale all phys/miis here and explicitly
- - * enable them in the device secific init function
- + * TODO: we should really disable all phys/miis here and explicitly
- + * enable them in the device specific init function
- */
- /* disable port fetch/store dma */
- @@ -1556,16 +2209,18 @@
- ltq_switch_w32(0x40, PCE_PMAP2);
- ltq_switch_w32(0x40, PCE_PMAP3);
- +//TODO search XRX200_BM_GCTRL_FR_RBC
- +
- /* RMON Counter Enable for all physical ports */
- - for (i = 0; i < 7; i++)
- - ltq_switch_w32(0x1, BM_PCFG(i));
- +// for (i = 0; i < 7; i++)
- +// ltq_switch_w32(0x1, BM_PCFG(i));
- /* disable auto polling */
- ltq_mdio_w32(0x0, MDIO_CLK_CFG0);
- /* enable port statistic counters */
- - for (i = 0; i < 7; i++)
- - ltq_switch_w32(0x1, BM_PCFGx(i));
- +// for (i = 0; i < 7; i++)
- +// ltq_switch_w32(0x1, BM_PCFGx(i));
- /* set IPG to 12 */
- ltq_pmac_w32_mask(PMAC_IPG_MASK, 0xb, PMAC_RX_IPG);
- @@ -1597,68 +2252,92 @@
- xrx200sw_write_x(1, XRX200_BM_QUEUE_GCTRL_GL_MOD, 0);
- for (i = 0; i < XRX200_MAX_VLAN; i++)
- - hw->vlan_vid[i] = i;
- + priv->vlan_vid[i] = i;
- }
- -static void xrx200_hw_cleanup(struct xrx200_hw *hw)
- +static void xrx200_hw_cleanup(struct xrx200_priv *priv)
- {
- - int i;
- + int i, idx;
- /* disable the switch */
- ltq_mdio_w32_mask(MDIO_GLOB_ENABLE, 0, MDIO_GLOB);
- - /* free the channels and IRQs */
- - for (i = 0; i < 2; i++) {
- - ltq_dma_free(&hw->chan[i].dma);
- - if (hw->chan[i].dma.irq)
- - free_irq(hw->chan[i].dma.irq, hw);
- +
- + for (i = 0; i < MAX_TX_RINGS; i++) {
- + struct xrx200_tx_ring *ring = &priv->tx[i];
- +
- + ltq_dma_free(&ring->dma);
- +
- +//TODO cleanup path
- +// ring->dma.desc_base = NULL;
- }
- - /* free the allocated RX ring */
- - for (i = 0; i < LTQ_DESC_NUM; i++)
- - dev_kfree_skb_any(hw->chan[XRX200_DMA_RX].skb[i]);
- + for (i = 0; i < MAX_RX_RINGS; i++) {
- + struct xrx200_rx_ring *ring = &priv->rx[i];
- +
- + ltq_dma_free(&ring->dma);
- +
- + /* free the allocated RX ring */
- + for (idx = 0; idx < ring->num; idx++) {
- + if (ring->skb_list[idx].skb)
- + dev_kfree_skb_any(ring->skb_list[idx].skb);
- +
- + ring->skb_list[idx].skb = NULL;
- + }
- + }
- /* clear the mdio bus */
- - mdiobus_unregister(hw->mii_bus);
- - mdiobus_free(hw->mii_bus);
- + mdiobus_unregister(priv->mii_bus);
- + mdiobus_free(priv->mii_bus);
- /* release the clock */
- - clk_disable(hw->clk);
- - clk_put(hw->clk);
- + clk_disable(priv->clk);
- + clk_put(priv->clk);
- }
- -static int xrx200_of_mdio(struct xrx200_hw *hw, struct device_node *np)
- +static int xrx200_of_mdio(struct xrx200_priv *priv, struct device_node *np)
- {
- - hw->mii_bus = mdiobus_alloc();
- - if (!hw->mii_bus)
- + priv->mii_bus = mdiobus_alloc();
- + if (!priv->mii_bus)
- return -ENOMEM;
- - hw->mii_bus->read = xrx200_mdio_rd;
- - hw->mii_bus->write = xrx200_mdio_wr;
- - hw->mii_bus->name = "lantiq,xrx200-mdio";
- - snprintf(hw->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
- + priv->mii_bus->read = xrx200_mdio_rd;
- + priv->mii_bus->write = xrx200_mdio_wr;
- + priv->mii_bus->name = "lantiq,xrx200-mdio";
- + snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
- - if (of_mdiobus_register(hw->mii_bus, np)) {
- - mdiobus_free(hw->mii_bus);
- + if (of_mdiobus_register(priv->mii_bus, np)) {
- + mdiobus_free(priv->mii_bus);
- return -ENXIO;
- }
- return 0;
- }
- -static void xrx200_of_port(struct xrx200_priv *priv, struct device_node *port)
- +static int xrx200_of_port(struct xrx200_priv *priv, struct xrx200_iface *iface, struct device_node *port)
- {
- const __be32 *addr, *id = of_get_property(port, "reg", NULL);
- - struct xrx200_port *p = &priv->port[priv->num_port];
- + struct xrx200_port *p;
- if (!id)
- - return;
- + return -EINVAL;
- +
- + p = devm_kzalloc(priv->dev, sizeof(struct xrx200_port),
- + GFP_KERNEL);
- + if (!p) {
- + dev_err(priv->dev, "failed to allocate port structure\n");
- +
- + return -ENOMEM;
- + }
- - memset(p, 0, sizeof(struct xrx200_port));
- p->phy_node = of_parse_phandle(port, "phy-handle", 0);
- addr = of_get_property(p->phy_node, "reg", NULL);
- - if (!addr)
- - return;
- +
- + if (!addr) {
- + dev_err(priv->dev, "property 'reg' is missing\n");
- +
- + return -EINVAL;
- + }
- p->num = *id;
- p->phy_addr = *addr;
- @@ -1667,7 +2346,6 @@
- p->flags = XRX200_PORT_TYPE_MAC;
- else
- p->flags = XRX200_PORT_TYPE_PHY;
- - priv->num_port++;
- p->gpio = of_get_gpio_flags(port, 0, &p->gpio_flags);
- if (gpio_is_valid(p->gpio))
- @@ -1677,16 +2355,108 @@
- udelay(100);
- gpio_set_value(p->gpio, (p->gpio_flags & OF_GPIO_ACTIVE_LOW) ? (0) : (1));
- }
- +
- /* is this port a wan port ? */
- - if (priv->wan)
- - priv->hw->wan_map |= BIT(p->num);
- + if (iface->iftype & BIT(IF_TYPE_WAN))
- + priv->wan_map |= BIT(p->num);
- - priv->port_map |= BIT(p->num);
- + priv->d_port_map |= BIT(p->num);
- /* store the port id in the hw struct so we can map ports -> devices */
- - priv->hw->port_map[p->num] = priv->hw->num_devs;
- + priv->port_map[p->num] = iface;
- +
- + list_add(&p->port, &iface->ports);
- +
- + return 0;
- }
- +static void xrx200_get_stats64(struct net_device *dev,
- + struct rtnl_link_stats64 *storage)
- +{
- + struct xrx200_iface *iface = netdev_priv(dev);
- + unsigned int start;
- + int i;
- +
- + //TODO are there HW registers?
- +
- + do {
- + start = u64_stats_fetch_begin_irq(&iface->syncp);
- + storage->tx_errors = iface->tx_errors;
- + } while (u64_stats_fetch_retry_irq(&iface->syncp, start));
- +
- + for (i = 0; i < iface->num_tx_queues; i++) {
- + do {
- + start = u64_stats_fetch_begin_irq(&iface->txq[i].syncp);
- + storage->tx_packets += iface->txq[i].tx_packets;
- + storage->tx_bytes += iface->txq[i].tx_bytes;
- + storage->tx_errors += iface->txq[i].tx_errors;
- + storage->tx_dropped += iface->txq[i].tx_dropped;
- + } while (u64_stats_fetch_retry_irq(&iface->txq[i].syncp, start));
- + }
- +
- + do {
- + start = u64_stats_fetch_begin_irq(&iface->rxq[0].syncp);
- + storage->rx_packets = iface->rxq[0].rx_packets;
- + storage->rx_bytes = iface->rxq[0].rx_bytes;
- + storage->rx_dropped = iface->rxq[0].rx_dropped;
- + } while (u64_stats_fetch_retry_irq(&iface->rxq[0].syncp, start));
- +
- +}
- +
- +//TODO this too?
- +// * int (*ndo_change_mtu)(struct net_device *dev, int new_mtu);
- +// * Called when a user wants to change the Maximum Transfer Unit
- +// * of a device.
- +
- +u16 glqid=0;
- +
- +static u16 xrx200_select_queue(struct net_device *dev, struct sk_buff *skb,
- + void *accel_priv, select_queue_fallback_t fallback)
- +{
- + u16 qid;
- +
- + /*
- + * TODO?
- + * The SoC seems to be slowed down by tx housekeeping
- + * for the highest speed you need to schedule tx housekeeping
- + * interrupt to the other VPE
- + *
- + * The default netdev queue select causes TX speed drops as
- + * userspace is sometimes scheduled to the same VPE which is making
- + * housekeeping.
- + *
- + * The TX DMAs IRQ should be constrained to a single VPE as the
- + * cycling through them will cause 50% of time to have the housekeeping
- + * on the same VPE.
- + */
- +
- + //TODO cornercases: single queue, singlecore, constrained affinity
- +
- +
- +#if 0
- + if (skb_rx_queue_recorded(skb))
- + qid = skb_get_rx_queue(skb);
- + else
- + qid = fallback(dev, skb);
- +//#else
- +// qid = glqid?1:0;
- +
- +// glqid = !glqid;
- +#endif
- +
- + //https://elixir.bootlin.com/linux/v5.1-rc5/source/kernel/irq/cpuhotplug.c#L39
- +
- + //HACK only two VPEs max
- + if (smp_processor_id()) {
- + qid = 0;
- + } else {
- + qid = 1;
- + }
- +
- + return qid;
- +}
- +
- +
- static const struct net_device_ops xrx200_netdev_ops = {
- .ndo_init = xrx200_init,
- .ndo_open = xrx200_open,
- @@ -1694,174 +2464,321 @@
- .ndo_start_xmit = xrx200_start_xmit,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
- - .ndo_get_stats = xrx200_get_stats,
- .ndo_tx_timeout = xrx200_tx_timeout,
- + .ndo_get_stats64 = xrx200_get_stats64,
- +// .ndo_select_queue = xrx200_select_queue,
- };
- -static void xrx200_of_iface(struct xrx200_hw *hw, struct device_node *iface, struct device *dev)
- +static int xrx200_of_iface(struct xrx200_priv *priv, struct device_node *node, struct device *dev)
- {
- - struct xrx200_priv *priv;
- struct device_node *port;
- - const __be32 *wan;
- +// const __be32 *wan;
- const u8 *mac;
- + struct net_device *net_dev;
- + struct xrx200_iface *iface;
- + int ret;
- + int i;
- + /* get interface MII value */
- +// const __be32 *id = of_get_property(port, "reg", NULL);
- +
- + //TODO add queues + ring mapping user definition into devicetree
- +
- + //TODO hardcoded num queues
- + //NOTICE allocated iface struct
- /* alloc the network device */
- - hw->devs[hw->num_devs] = alloc_etherdev(sizeof(struct xrx200_priv));
- - if (!hw->devs[hw->num_devs])
- - return;
- + net_dev = devm_alloc_etherdev_mqs(dev, sizeof(struct xrx200_iface),
- + MAX_TX_QUEUES, 1);
- +
- + if (!net_dev) {
- + dev_err(priv->dev, "failed to allocate net device\n");
- +
- + return -ENOMEM;
- + }
- +
- + //NOTICE iface struct allocated in etherdev mqs
- + iface = netdev_priv(net_dev);
- +
- + //TODO iface is array after netdev, container_of?
- + iface->net_dev = net_dev;
- + iface->priv = priv;
- + iface->num_tx_queues = 2; //TODO devicetree?
- +
- + net_dev->netdev_ops = &xrx200_netdev_ops; //TODO dvakrat
- + SET_NETDEV_DEV(net_dev, priv->dev);
- + net_dev->min_mtu = ETH_ZLEN;
- + net_dev->max_mtu = XRX200_DMA_DATA_LEN;
- +
- + net_dev->features |= NETIF_F_SG ;
- + net_dev->hw_features |= NETIF_F_SG;
- + net_dev->vlan_features |= NETIF_F_SG;
- /* setup the network device */
- - strcpy(hw->devs[hw->num_devs]->name, "eth%d");
- - hw->devs[hw->num_devs]->netdev_ops = &xrx200_netdev_ops;
- - hw->devs[hw->num_devs]->watchdog_timeo = XRX200_TX_TIMEOUT;
- - hw->devs[hw->num_devs]->needed_headroom = XRX200_HEADROOM;
- - SET_NETDEV_DEV(hw->devs[hw->num_devs], dev);
- -
- - /* setup our private data */
- - priv = netdev_priv(hw->devs[hw->num_devs]);
- - priv->hw = hw;
- - priv->id = hw->num_devs;
- + strcpy(net_dev->name, "eth%d");
- + net_dev->netdev_ops = &xrx200_netdev_ops;
- + net_dev->watchdog_timeo = XRX200_TX_TIMEOUT;
- + net_dev->needed_headroom = XRX200_HEADROOM;
- - mac = of_get_mac_address(iface);
- + mac = of_get_mac_address(node);
- if (mac)
- - memcpy(priv->mac, mac, ETH_ALEN);
- + memcpy(iface->mac, mac, ETH_ALEN);
- +
- + /* should the switch be enabled on this interface ? */
- + if (of_find_property(node, "lantiq,switch", NULL))
- + iface->iftype |= BIT(IF_TYPE_SWITCH);
- /* is this the wan interface ? */
- - wan = of_get_property(iface, "lantiq,wan", NULL);
- - if (wan && (*wan == 1))
- - priv->wan = 1;
- + if (of_find_property(node, "lantiq,wan", NULL))
- + iface->iftype |= BIT(IF_TYPE_WAN);
- - /* should the switch be enabled on this interface ? */
- - if (of_find_property(iface, "lantiq,switch", NULL))
- - priv->sw = 1;
- + INIT_LIST_HEAD(&iface->ports);
- /* load the ports that are part of the interface */
- - for_each_child_of_node(iface, port)
- + for_each_child_of_node(node, port)
- if (of_device_is_compatible(port, "lantiq,xrx200-pdi-port"))
- - xrx200_of_port(priv, port);
- + if (xrx200_of_port(priv, iface, port)) {
- + return -EINVAL;
- + }
- - /* register the actual device */
- - if (!register_netdev(hw->devs[hw->num_devs]))
- - hw->num_devs++;
- -}
- + iface->txq = devm_kzalloc(priv->dev, iface->num_tx_queues *
- + sizeof(struct xrx200_tx_queue),
- + GFP_KERNEL);
- +
- + iface->rxq = devm_kzalloc(priv->dev, sizeof(struct xrx200_rx_queue),
- + GFP_KERNEL);
- +
- + for (i = 0; i < iface->num_tx_queues; i++) {
- + struct xrx200_tx_queue *txq = &iface->txq[i];
- + //TODO shorten by txq pointer
- +
- + txq->ring = &priv->tx[i % MAX_TX_RINGS];
- + txq->nqueue = netdev_get_tx_queue(net_dev, i % MAX_TX_RINGS);
- +
- + /* local ring pointers */
- + txq->head = 0;
- + txq->tail = 0;
- -static struct xrx200_hw xrx200_hw;
- + //split from ring length
- + txq->num = txq->ring->num / 1;
- + //TODO divide by queue count per ring list_for_each txq->ring->queues
- +
- + /* array of descriptors */
- + txq->skb_list = devm_kzalloc(priv->dev,
- + txq->num * sizeof(struct xrx200_tx_skb),
- + GFP_KERNEL);
- +
- + //queue can be more than cpus
- +
- + list_add(&txq->queue, &txq->ring->queues);
- + }
- +
- + iface->rxq[0].priv = priv;
- + iface->rxq[0].ring = &priv->rx[0];
- +
- + ret = register_netdev(net_dev);
- + if (ret)
- + return ret;
- +
- + if (iface->iftype & BIT(IF_TYPE_SWITCH))
- + xrx200sw_init(iface);
- +
- + list_add(&iface->iface, &priv->ifaces);
- +
- + return 0;
- +}
- static int xrx200_probe(struct platform_device *pdev)
- {
- + struct device *dev = &pdev->dev;
- struct resource *res[4];
- struct device_node *mdio_np, *iface_np, *phy_np;
- struct of_phandle_iterator it;
- int err;
- int i;
- + struct xrx200_priv *priv;
- +#ifndef SW_POLLING
- + struct list_head *pos;
- + unsigned int reg = 0;
- +#endif
- +
- + priv = devm_kzalloc(dev, sizeof(struct xrx200_priv),
- + GFP_KERNEL);
- + if (!priv) {
- + dev_err(dev, "failed to allocate priv structure\n");
- +
- + return -ENOMEM;
- + }
- +
- + priv->dev = dev;
- +
- +//dev_set_drvdata(dev, priv); ???
- /* load the memory ranges */
- for (i = 0; i < 4; i++) {
- res[i] = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (!res[i]) {
- - dev_err(&pdev->dev, "failed to get resources\n");
- + dev_err(dev, "failed to get resources\n");
- return -ENOENT;
- }
- }
- - xrx200_switch_membase = devm_ioremap_resource(&pdev->dev, res[0]);
- - xrx200_mdio_membase = devm_ioremap_resource(&pdev->dev, res[1]);
- - xrx200_mii_membase = devm_ioremap_resource(&pdev->dev, res[2]);
- - xrx200_pmac_membase = devm_ioremap_resource(&pdev->dev, res[3]);
- +
- + xrx200_switch_membase = devm_ioremap_resource(dev, res[0]);
- + xrx200_mdio_membase = devm_ioremap_resource(dev, res[1]);
- + xrx200_mii_membase = devm_ioremap_resource(dev, res[2]);
- + xrx200_pmac_membase = devm_ioremap_resource(dev, res[3]);
- +
- if (!xrx200_switch_membase || !xrx200_mdio_membase ||
- !xrx200_mii_membase || !xrx200_pmac_membase) {
- - dev_err(&pdev->dev, "failed to request and remap io ranges \n");
- + dev_err(dev, "failed to request and remap io ranges \n");
- return -ENOMEM;
- }
- - of_for_each_phandle(&it, err, pdev->dev.of_node, "lantiq,phys", NULL, 0) {
- + of_for_each_phandle(&it, err, dev->of_node, "lantiq,phys", NULL, 0) {
- phy_np = it.node;
- if (phy_np) {
- struct platform_device *phy = of_find_device_by_node(phy_np);
- -
- +
- of_node_put(phy_np);
- if (!platform_get_drvdata(phy))
- return -EPROBE_DEFER;
- }
- }
- +//TODO ? devm_clk_get
- /* get the clock */
- - xrx200_hw.clk = clk_get(&pdev->dev, NULL);
- - if (IS_ERR(xrx200_hw.clk)) {
- - dev_err(&pdev->dev, "failed to get clock\n");
- - return PTR_ERR(xrx200_hw.clk);
- + priv->clk = clk_get(dev, NULL);
- + if (IS_ERR(priv->clk)) {
- + dev_err(dev, "failed to get clock\n");
- + return PTR_ERR(priv->clk);
- }
- /* bring up the dma engine and IP core */
- - xrx200_dma_init(&pdev->dev, &xrx200_hw);
- - xrx200_hw_init(&xrx200_hw);
- - tasklet_init(&xrx200_hw.chan[XRX200_DMA_TX].tasklet, xrx200_tx_housekeeping, (u32) &xrx200_hw.chan[XRX200_DMA_TX]);
- - tasklet_init(&xrx200_hw.chan[XRX200_DMA_TX_2].tasklet, xrx200_tx_housekeeping, (u32) &xrx200_hw.chan[XRX200_DMA_TX_2]);
- + err = xrx200_dma_init(priv);
- + if (err)
- + return err;
- +
- + /* enable clock gate */
- + err = clk_prepare_enable(priv->clk);
- + if (err)
- + goto err_uninit_dma;
- +
- + xrx200_hw_init(priv);
- +
- + /* set wan port mask */
- + ltq_pmac_w32(priv->wan_map, PMAC_EWAN);
- +
- +
- + /* global dummy netdev for napi, for all DMA rings */
- + init_dummy_netdev(&priv->dummy_net);
- +
- + /* setup NAPI */
- + for (i = 0; i < MAX_RX_RINGS; i++) {
- + netif_napi_add(&priv->dummy_net, &priv->rx[i].napi,
- + xrx200_poll_rx, 32); //32 TODO value by number of queues?
- + }
- +
- + for (i = 0; i < MAX_TX_RINGS; i++) {
- + netif_tx_napi_add(&priv->dummy_net, &priv->tx[i].napi,
- + xrx200_tx_housekeeping, 48); //TODO number by queues?
- + }
- /* bring up the mdio bus */
- - mdio_np = of_find_compatible_node(pdev->dev.of_node, NULL,
- + mdio_np = of_find_compatible_node(dev->of_node, NULL,
- "lantiq,xrx200-mdio");
- if (mdio_np)
- - if (xrx200_of_mdio(&xrx200_hw, mdio_np))
- - dev_err(&pdev->dev, "mdio probe failed\n");
- + if (xrx200_of_mdio(priv, mdio_np))
- + dev_err(dev, "mdio probe failed\n"); //TODO fail path?
- +
- + INIT_LIST_HEAD(&priv->ifaces);
- /* load the interfaces */
- - for_each_child_of_node(pdev->dev.of_node, iface_np)
- - if (of_device_is_compatible(iface_np, "lantiq,xrx200-pdi")) {
- - if (xrx200_hw.num_devs < XRX200_MAX_DEV)
- - xrx200_of_iface(&xrx200_hw, iface_np, &pdev->dev);
- - else
- - dev_err(&pdev->dev,
- - "only %d interfaces allowed\n",
- - XRX200_MAX_DEV);
- - }
- + for_each_child_of_node(dev->of_node, iface_np)
- + if (of_device_is_compatible(iface_np, "lantiq,xrx200-pdi")) {
- + err = xrx200_of_iface(priv, iface_np, dev);
- +
- + if (err) {
- + //printk?
- + goto err_unprepare_clk;
- + }
- + }
- - if (!xrx200_hw.num_devs) {
- - xrx200_hw_cleanup(&xrx200_hw);
- - dev_err(&pdev->dev, "failed to load interfaces\n");
- - return -ENOENT;
- +#ifndef SW_POLLING
- +//TODO this is sort of ugly, but original way seems to be weird
- +//double register fills (once for Sw and second for WAN into MDIO_CLK_CFG0)
- +//RFC if one can RMW MDIO_CLK_CFG0 after setting MDIO_CLK_CFG1, it could be split
- +//and put back to xrx200_init
- +//TODO maybe put before xrx200_of_iface
- + reg = 0;
- +
- + list_for_each(pos, &priv->ifaces) {
- + struct list_head *port_list;
- + struct xrx200_iface *iface = list_entry(pos,
- + struct xrx200_iface,
- + iface);
- +
- + list_for_each(port_list, &iface->ports) {
- + struct xrx200_port *port =
- + list_entry(port_list,
- + struct xrx200_port,
- + port);;
- +
- + reg |= BIT(port->num);
- + }
- }
- - xrx200sw_init(&xrx200_hw);
- + ltq_mdio_w32(reg, MDIO_CLK_CFG0);
- + ltq_mdio_w32(MDIO1_25MHZ, MDIO_CLK_CFG1);
- +#endif
- - /* set wan port mask */
- - ltq_pmac_w32(xrx200_hw.wan_map, PMAC_EWAN);
- + platform_set_drvdata(pdev, priv);
- - for (i = 0; i < xrx200_hw.num_devs; i++) {
- - xrx200_hw.chan[XRX200_DMA_RX].devs[i] = xrx200_hw.devs[i];
- - xrx200_hw.chan[XRX200_DMA_TX].devs[i] = xrx200_hw.devs[i];
- - xrx200_hw.chan[XRX200_DMA_TX_2].devs[i] = xrx200_hw.devs[i];
- - }
- + return 0;
- - /* setup NAPI */
- - init_dummy_netdev(&xrx200_hw.chan[XRX200_DMA_RX].dummy_dev);
- - netif_napi_add(&xrx200_hw.chan[XRX200_DMA_RX].dummy_dev,
- - &xrx200_hw.chan[XRX200_DMA_RX].napi, xrx200_poll_rx, 32);
- +err_unprepare_clk:
- +//TODO split for fail inside xrx200_of_iface, unregister_netdevs from list
- + clk_disable_unprepare(priv->clk);
- - platform_set_drvdata(pdev, &xrx200_hw);
- +err_uninit_dma:
- +//TODO rename to xrx200_dma_cleanup? maybe...
- + xrx200_hw_cleanup(priv);
- - return 0;
- + return err;
- }
- static int xrx200_remove(struct platform_device *pdev)
- {
- - struct net_device *dev = platform_get_drvdata(pdev);
- - struct xrx200_priv *priv;
- + int i;
- + struct xrx200_priv *priv = platform_get_drvdata(pdev);
- + struct xrx200_iface *iface;
- + struct list_head *pos;
- - if (!dev)
- - return 0;
- + /* free stack related instances */
- + list_for_each(pos, &priv->ifaces) {
- + iface = list_entry(pos, struct xrx200_iface, iface);
- - priv = netdev_priv(dev);
- + netif_tx_stop_all_queues(iface->net_dev);
- + }
- - /* free stack related instances */
- - netif_stop_queue(dev);
- - netif_napi_del(&xrx200_hw.chan[XRX200_DMA_RX].napi);
- + for (i = 0; i < MAX_TX_RINGS; i++) {
- + netif_napi_del(&priv->tx[i].napi);
- + }
- - /* shut down hardware */
- - xrx200_hw_cleanup(&xrx200_hw);
- + for (i = 0; i < MAX_RX_RINGS; i++) {
- + netif_napi_del(&priv->rx[i].napi);
- + }
- /* remove the actual device */
- - unregister_netdev(dev);
- - free_netdev(dev);
- + list_for_each(pos, &priv->ifaces) {
- + iface = list_entry(pos, struct xrx200_iface, iface);
- +
- + unregister_netdev(iface->net_dev);
- + }
- +
- + /* release the clock */
- + clk_disable_unprepare(priv->clk);
- +
- + /* shut down hardware */
- + xrx200_hw_cleanup(priv);
- return 0;
- }
- --- a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h 2019-08-06 19:06:58.000000000 +0200
- +++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h 2019-08-13 07:02:09.801309128 +0200
- @@ -19,7 +19,7 @@
- #define LTQ_DMA_H__
- #define LTQ_DESC_SIZE 0x08 /* each descriptor is 64bit */
- -#define LTQ_DESC_NUM 0x40 /* 64 descriptors / channel */
- +#define LTQ_DESC_NUM 0x80 /* 128 descriptors / channel */
- #define LTQ_DMA_OWN BIT(31) /* owner bit */
- #define LTQ_DMA_C BIT(30) /* complete bit */
- --- a/arch/mips/lantiq/xway/dma.c 2019-08-06 19:06:58.000000000 +0200
- +++ b/arch/mips/lantiq/xway/dma.c 2019-08-13 07:03:54.169004352 +0200
- @@ -49,7 +49,10 @@
- #define DMA_IRQ_ACK 0x7e /* IRQ status register */
- #define DMA_POLL BIT(31) /* turn on channel polling */
- #define DMA_CLK_DIV4 BIT(6) /* polling clock divider */
- -#define DMA_2W_BURST BIT(1) /* 2 word burst length */
- +#define DMA_1W_BURST 0x0 /* 1 word burst length/no burst */
- +#define DMA_2W_BURST 0x1 /* 2 word burst length */
- +#define DMA_4W_BURST 0x2 /* 4 word burst length */
- +#define DMA_8W_BURST 0x3 /* 8 word burst length */
- #define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */
- #define DMA_ETOP_ENDIANNESS (0xf << 8) /* endianness swap etop channels */
- #define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */
- @@ -137,7 +140,7 @@
- spin_lock_irqsave(<q_dma_lock, flags);
- ltq_dma_w32(ch->nr, LTQ_DMA_CS);
- ltq_dma_w32(ch->phys, LTQ_DMA_CDBA);
- - ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN);
- + ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN); //0xff mask
- ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
- wmb();
- ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL);
- @@ -154,7 +157,13 @@
- ltq_dma_alloc(ch);
- spin_lock_irqsave(<q_dma_lock, flags);
- - ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
- +
- +//DMA_DESCPT BIT(3) //end of descriptor
- +//BIT(1) //end of packet
- +// ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
- + ltq_dma_w32(BIT(1), LTQ_DMA_CIE);
- +
- +
- ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
- ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL);
- spin_unlock_irqrestore(<q_dma_lock, flags);
- @@ -193,6 +202,12 @@
- ltq_dma_w32(p, LTQ_DMA_PS);
- switch (p) {
- case DMA_PORT_ETOP:
- +
- + /* 8 words burst, data must be aligned on 4*N bytes or freeze */
- +//TODO? different bursts for TX and RX (RX is fine at 1G eth)
- + ltq_dma_w32_mask(0x3c, (DMA_8W_BURST << 4) | (DMA_8W_BURST << 2),
- + LTQ_DMA_PCTRL);
- +
- /*
- * Tell the DMA engine to swap the endianness of data frames and
- * drop packets if the channel arbitration fails.
- @@ -240,10 +255,18 @@
- for (i = 0; i < DMA_MAX_CHANNEL; i++) {
- ltq_dma_w32(i, LTQ_DMA_CS);
- ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL);
- - ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL);
- ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
- }
- +//TODO 0x100 << 4 fastest TX without fragments
- +// 0x100 for fragments timeouts, 0x10 only under really _heavy_ load
- +//TODO not dependent on channel select (LTQ_DMA_CS), why it was in for cycle
- + ltq_dma_w32(DMA_POLL | (0x10 << 4), LTQ_DMA_CPOLL);
- +
- +//TODO packet arbitration ???, test different values
- +//0x3ff << 16 multiple burst count, 1<<30 multiple burst arbitration, 1<<31 packet arbitration, 1<<0 reset (!)
- +// ltq_dma_w32((1 << 31) | 0x40000, LTQ_DMA_CTRL);
- +
- id = ltq_dma_r32(LTQ_DMA_ID);
- dev_info(&pdev->dev,
- "Init done - hw rev: %X, ports: %d, channels: %d\n",
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement