embox
1/**
2* @file
3*
4* @date 10.05.2016
5* @author: Anton Bondarev
6*/
7#include <errno.h>8#include <stdint.h>9
10#include <util/log.h>11
12#include <kernel/irq.h>13
14#include <net/skbuff.h>15#include <net/netdevice.h>16#include <net/l0/net_entry.h>17#include <net/l2/ethernet.h>18#include <net/inetdevice.h>19#include <net/util/show_packet.h>20
21#include <asm/io.h>22
23#include <embox/unit.h>24
25EMBOX_UNIT_INIT(mipsnet_init);26
27#define BASE_ADDR OPTION_GET(NUMBER,base_addr)28#define IRQ_NUM OPTION_GET(NUMBER,irq_num)29
30/*
31* Net status/control block as seen by sw in the core.
32*/
33struct mipsnet_regs {34/*35* Device info for probing, reads as MIPSNET%d where %d is some
36* form of version.
37*/
38uint64_t devId; /*0x00 */39
40/*41* read only busy flag.
42* Set and cleared by the Net Device to indicate that an rx or a tx
43* is in progress.
44*/
45uint32_t busy; /*0x08 */46
47/*48* Set by the Net Device.
49* The device will set it once data has been received.
50* The value is the number of bytes that should be read from
51* rxDataBuffer. The value will decrease till 0 until all the data
52* from rxDataBuffer has been read.
53*/
54uint32_t rxDataCount; /*0x0c */55#define MIPSNET_MAX_RXTX_DATACOUNT (1 << 16)56
57/*58* Settable from the MIPS core, cleared by the Net Device.
59* The core should set the number of bytes it wants to send,
60* then it should write those bytes of data to txDataBuffer.
61* The device will clear txDataCount has been processed (not
62* necessarily sent).
63*/
64uint32_t txDataCount; /*0x10 */65
66/*67* Interrupt control
68*
69* Used to clear the interrupted generated by this dev.
70* Write a 1 to clear the interrupt. (except bit31).
71*
72* Bit0 is set if it was a tx-done interrupt.
73* Bit1 is set when new rx-data is available.
74* Until this bit is cleared there will be no other RXs.
75*
76* Bit31 is used for testing, it clears after a read.
77* Writing 1 to this bit will cause an interrupt to be generated.
78* To clear the test interrupt, write 0 to this register.
79*/
80uint32_t interruptControl; /*0x14 */81#define MIPSNET_INTCTL_TXDONE (1u << 0)82#define MIPSNET_INTCTL_RXDONE (1u << 1)83#define MIPSNET_INTCTL_TESTBIT (1u << 31)84
85/*86* Readonly core-specific interrupt info for the device to signal
87* the core. The meaning of the contents of this field might change.
88*/
89/* XXX: the whole memIntf interrupt scheme is messy: the device90* should have no control what so ever of what VPE/register set is
91* being used.
92* The MemIntf should only expose interrupt lines, and something in
93* the config should be responsible for the line<->core/vpe bindings.
94*/
95uint32_t interruptInfo; /*0x18 */96
97/*98* This is where the received data is read out.
99* There is more data to read until rxDataReady is 0.
100* Only 1 byte at this regs offset is used.
101*/
102uint32_t rxDataBuffer; /*0x1c */103
104/*105* This is where the data to transmit is written.
106* Data should be written for the amount specified in the
107* txDataCount register.
108* Only 1 byte at this regs offset is used.
109*/
110uint32_t txDataBuffer; /*0x20 */111};112
113static int mipsnet_xmit(struct net_device *dev, struct sk_buff *skb) {114struct mipsnet_regs *regs;115int i;116uint8_t *pdata;117
118show_packet(skb->mac.raw, skb->len, "xmit");119
120regs = (struct mipsnet_regs *)dev->base_addr;121pdata = skb->mac.raw;122
123out32(skb->len, ®s->txDataCount);124for(i = 0; i < skb->len; i++) {125out32((uint32_t)*pdata, ®s->txDataBuffer);126pdata++;127}128
129skb_free(skb);130return 0;131}
132
133static int mipsnet_open(struct net_device *dev) {134struct mipsnet_regs *regs;135
136regs = (struct mipsnet_regs *)dev->base_addr;137out32(MIPSNET_INTCTL_TESTBIT, ®s->interruptControl);138
139return 0;140}
141
142static int mipsnet_set_macaddr(struct net_device *dev, const void *addr) {143return 0;144}
145
146static const struct net_driver mipsnet_drv_ops = {147.xmit = mipsnet_xmit,148.start = mipsnet_open,149.set_macaddr = mipsnet_set_macaddr150};151
152static int mipsnet_rx(struct net_device *dev, size_t len) {153struct sk_buff *skb;154uint8_t *pdata;155struct mipsnet_regs *regs;156
157if (!len)158return len;159
160regs = (struct mipsnet_regs *)dev->base_addr;161
162skb = skb_alloc(len);163if (!skb) {164dev->stats.rx_dropped++;165return -ENOMEM;166}167pdata = (uint8_t*) skb->mac.raw;168for (; len > 0; len--, pdata++) {169*pdata = in32(®s->rxDataBuffer);170}171
172show_packet(skb->mac.raw, skb->len, "rx");173skb->dev = dev;174
175netif_rx(skb);176
177dev->stats.rx_packets++;178dev->stats.rx_bytes += len;179
180return len;181}
182
183static irq_return_t mipsnet_interrupt_handler(unsigned int irq, void *dev_id) {184struct net_device *dev = dev_id;185uint32_t int_flags;186irq_return_t ret = IRQ_NONE;187struct mipsnet_regs *regs;188
189if (irq != dev->irq)190goto out_badirq;191
192regs = (struct mipsnet_regs *)dev->base_addr;193
194/* TESTBIT is cleared on read. */195int_flags = in32(®s->interruptControl);196if (int_flags & MIPSNET_INTCTL_TESTBIT) {197/* TESTBIT takes effect after a write with 0. */198out32(0, ®s->interruptControl);199ret = IRQ_HANDLED;200} else if (int_flags & MIPSNET_INTCTL_TXDONE) {201/* Only one packet at a time, we are done. */202dev->stats.tx_packets++;203out32(MIPSNET_INTCTL_TXDONE, ®s->interruptControl);204ret = IRQ_HANDLED;205} else if (int_flags & MIPSNET_INTCTL_RXDONE) {206mipsnet_rx(dev, in32(®s->rxDataCount));207out32(MIPSNET_INTCTL_RXDONE, ®s->interruptControl);208ret = IRQ_HANDLED;209}210
211return ret;212
213out_badirq:214log_info("%s: irq %d for unknown device\n", dev->name, irq);215
216return ret;217}
218
219
220static int mipsnet_init(void) {221struct net_device *netdev;222int err;223
224netdev = etherdev_alloc(0);225if (!netdev) {226return -ENOMEM;227}228
229/*230* TODO: probe for these or load them from PARAM
231*/
232netdev->base_addr = BASE_ADDR;233netdev->irq = IRQ_NUM;234netdev->drv_ops = &mipsnet_drv_ops;235
236err = irq_attach(IRQ_NUM, mipsnet_interrupt_handler, 0, netdev, "mipsnet");237if (err) {238return err;239}240
241return inetdev_register_dev(netdev);242}
243