12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715 |
- // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
- /* ADIN1110 Low Power 10BASE-T1L Ethernet MAC-PHY
- * ADIN2111 2-Port Ethernet Switch with Integrated 10BASE-T1L PHY
- *
- * Copyright 2021 Analog Devices Inc.
- */
- #include <linux/bitfield.h>
- #include <linux/bits.h>
- #include <linux/cache.h>
- #include <linux/crc8.h>
- #include <linux/etherdevice.h>
- #include <linux/ethtool.h>
- #include <linux/if_bridge.h>
- #include <linux/interrupt.h>
- #include <linux/iopoll.h>
- #include <linux/gpio.h>
- #include <linux/kernel.h>
- #include <linux/mii.h>
- #include <linux/module.h>
- #include <linux/netdevice.h>
- #include <linux/regulator/consumer.h>
- #include <linux/phy.h>
- #include <linux/property.h>
- #include <linux/spi/spi.h>
- #include <net/switchdev.h>
- #include <asm/unaligned.h>
- #define ADIN1110_PHY_ID 0x1
- #define ADIN1110_RESET 0x03
- #define ADIN1110_SWRESET BIT(0)
- #define ADIN1110_CONFIG1 0x04
- #define ADIN1110_CONFIG1_SYNC BIT(15)
- #define ADIN1110_CONFIG2 0x06
- #define ADIN2111_P2_FWD_UNK2HOST BIT(12)
- #define ADIN2111_PORT_CUT_THRU_EN BIT(11)
- #define ADIN1110_CRC_APPEND BIT(5)
- #define ADIN1110_FWD_UNK2HOST BIT(2)
- #define ADIN1110_STATUS0 0x08
- #define ADIN1110_STATUS1 0x09
- #define ADIN2111_P2_RX_RDY BIT(17)
- #define ADIN1110_SPI_ERR BIT(10)
- #define ADIN1110_RX_RDY BIT(4)
- #define ADIN1110_IMASK1 0x0D
- #define ADIN2111_RX_RDY_IRQ BIT(17)
- #define ADIN1110_SPI_ERR_IRQ BIT(10)
- #define ADIN1110_RX_RDY_IRQ BIT(4)
- #define ADIN1110_TX_RDY_IRQ BIT(3)
- #define ADIN1110_MDIOACC 0x20
- #define ADIN1110_MDIO_TRDONE BIT(31)
- #define ADIN1110_MDIO_ST GENMASK(29, 28)
- #define ADIN1110_MDIO_OP GENMASK(27, 26)
- #define ADIN1110_MDIO_PRTAD GENMASK(25, 21)
- #define ADIN1110_MDIO_DEVAD GENMASK(20, 16)
- #define ADIN1110_MDIO_DATA GENMASK(15, 0)
- #define ADIN1110_TX_FSIZE 0x30
- #define ADIN1110_TX 0x31
- #define ADIN1110_TX_SPACE 0x32
- #define ADIN1110_MAC_ADDR_FILTER_UPR 0x50
- #define ADIN2111_MAC_ADDR_APPLY2PORT2 BIT(31)
- #define ADIN1110_MAC_ADDR_APPLY2PORT BIT(30)
- #define ADIN2111_MAC_ADDR_TO_OTHER_PORT BIT(17)
- #define ADIN1110_MAC_ADDR_TO_HOST BIT(16)
- #define ADIN1110_MAC_ADDR_FILTER_LWR 0x51
- #define ADIN1110_MAC_ADDR_MASK_UPR 0x70
- #define ADIN1110_MAC_ADDR_MASK_LWR 0x71
- #define ADIN1110_RX_FSIZE 0x90
- #define ADIN1110_RX 0x91
- #define ADIN2111_RX_P2_FSIZE 0xC0
- #define ADIN2111_RX_P2 0xC1
- #define ADIN1110_CLEAR_STATUS0 0xFFF
- /* MDIO_OP codes */
- #define ADIN1110_MDIO_OP_WR 0x1
- #define ADIN1110_MDIO_OP_RD 0x3
- #define ADIN1110_CD BIT(7)
- #define ADIN1110_WRITE BIT(5)
- #define ADIN1110_MAX_BUFF 2048
- #define ADIN1110_MAX_FRAMES_READ 64
- #define ADIN1110_WR_HEADER_LEN 2
- #define ADIN1110_FRAME_HEADER_LEN 2
- #define ADIN1110_INTERNAL_SIZE_HEADER_LEN 2
- #define ADIN1110_RD_HEADER_LEN 3
- #define ADIN1110_REG_LEN 4
- #define ADIN1110_FEC_LEN 4
- #define ADIN1110_PHY_ID_VAL 0x0283BC91
- #define ADIN2111_PHY_ID_VAL 0x0283BCA1
- #define ADIN_MAC_MAX_PORTS 2
- #define ADIN_MAC_MAX_ADDR_SLOTS 16
- #define ADIN_MAC_MULTICAST_ADDR_SLOT 0
- #define ADIN_MAC_BROADCAST_ADDR_SLOT 1
- #define ADIN_MAC_P1_ADDR_SLOT 2
- #define ADIN_MAC_P2_ADDR_SLOT 3
- #define ADIN_MAC_FDB_ADDR_SLOT 4
- DECLARE_CRC8_TABLE(adin1110_crc_table);
- enum adin1110_chips_id {
- ADIN1110_MAC = 0,
- ADIN2111_MAC,
- };
- struct adin1110_cfg {
- enum adin1110_chips_id id;
- char name[MDIO_NAME_SIZE];
- u32 phy_ids[PHY_MAX_ADDR];
- u32 ports_nr;
- u32 phy_id_val;
- };
- struct adin1110_port_priv {
- struct adin1110_priv *priv;
- struct net_device *netdev;
- struct net_device *bridge;
- struct phy_device *phydev;
- struct work_struct tx_work;
- u64 rx_packets;
- u64 tx_packets;
- u64 rx_bytes;
- u64 tx_bytes;
- struct work_struct rx_mode_work;
- u32 flags;
- struct sk_buff_head txq;
- u32 nr;
- u32 state;
- struct adin1110_cfg *cfg;
- };
- struct adin1110_priv {
- struct mutex lock; /* protect spi */
- spinlock_t state_lock; /* protect RX mode */
- struct mii_bus *mii_bus;
- struct spi_device *spidev;
- bool append_crc;
- struct adin1110_cfg *cfg;
- u32 tx_space;
- u32 irq_mask;
- bool forwarding;
- int irq;
- struct adin1110_port_priv *ports[ADIN_MAC_MAX_PORTS];
- char mii_bus_name[MII_BUS_ID_SIZE];
- u8 data[ADIN1110_MAX_BUFF] ____cacheline_aligned;
- };
- struct adin1110_switchdev_event_work {
- struct work_struct work;
- struct switchdev_notifier_fdb_info fdb_info;
- struct adin1110_port_priv *port_priv;
- unsigned long event;
- };
- static struct adin1110_cfg adin1110_cfgs[] = {
- {
- .id = ADIN1110_MAC,
- .name = "adin1110",
- .phy_ids = {1},
- .ports_nr = 1,
- .phy_id_val = ADIN1110_PHY_ID_VAL,
- },
- {
- .id = ADIN2111_MAC,
- .name = "adin2111",
- .phy_ids = {1, 2},
- .ports_nr = 2,
- .phy_id_val = ADIN2111_PHY_ID_VAL,
- },
- };
- static u8 adin1110_crc_data(u8 *data, u32 len)
- {
- return crc8(adin1110_crc_table, data, len, 0);
- }
- static int adin1110_read_reg(struct adin1110_priv *priv, u16 reg, u32 *val)
- {
- u32 header_len = ADIN1110_RD_HEADER_LEN;
- u32 read_len = ADIN1110_REG_LEN;
- struct spi_transfer t = {0};
- int ret;
- priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg);
- priv->data[1] = FIELD_GET(GENMASK(7, 0), reg);
- priv->data[2] = 0x00;
- if (priv->append_crc) {
- priv->data[2] = adin1110_crc_data(&priv->data[0], 2);
- priv->data[3] = 0x00;
- header_len++;
- }
- if (priv->append_crc)
- read_len++;
- memset(&priv->data[header_len], 0, read_len);
- t.tx_buf = &priv->data[0];
- t.rx_buf = &priv->data[0];
- t.len = read_len + header_len;
- ret = spi_sync_transfer(priv->spidev, &t, 1);
- if (ret)
- return ret;
- if (priv->append_crc) {
- u8 recv_crc;
- u8 crc;
- crc = adin1110_crc_data(&priv->data[header_len],
- ADIN1110_REG_LEN);
- recv_crc = priv->data[header_len + ADIN1110_REG_LEN];
- if (crc != recv_crc) {
- dev_err_ratelimited(&priv->spidev->dev, "CRC error.");
- return -EBADMSG;
- }
- }
- *val = get_unaligned_be32(&priv->data[header_len]);
- return ret;
- }
- static int adin1110_write_reg(struct adin1110_priv *priv, u16 reg, u32 val)
- {
- u32 header_len = ADIN1110_WR_HEADER_LEN;
- u32 write_len = ADIN1110_REG_LEN;
- priv->data[0] = ADIN1110_CD | ADIN1110_WRITE | FIELD_GET(GENMASK(12, 8), reg);
- priv->data[1] = FIELD_GET(GENMASK(7, 0), reg);
- if (priv->append_crc) {
- priv->data[2] = adin1110_crc_data(&priv->data[0], header_len);
- header_len++;
- }
- put_unaligned_be32(val, &priv->data[header_len]);
- if (priv->append_crc) {
- priv->data[header_len + write_len] = adin1110_crc_data(&priv->data[header_len],
- write_len);
- write_len++;
- }
- return spi_write(priv->spidev, &priv->data[0], header_len + write_len);
- }
- static int adin1110_set_bits(struct adin1110_priv *priv, u16 reg,
- unsigned long mask, unsigned long val)
- {
- u32 write_val;
- int ret;
- ret = adin1110_read_reg(priv, reg, &write_val);
- if (ret < 0)
- return ret;
- set_mask_bits(&write_val, mask, val);
- return adin1110_write_reg(priv, reg, write_val);
- }
- static int adin1110_round_len(int len)
- {
- /* can read/write only mutiples of 4 bytes of payload */
- len = ALIGN(len, 4);
- /* NOTE: ADIN1110_WR_HEADER_LEN should be used for write ops. */
- if (len + ADIN1110_RD_HEADER_LEN > ADIN1110_MAX_BUFF)
- return -EINVAL;
- return len;
- }
- static int adin1110_read_fifo(struct adin1110_port_priv *port_priv)
- {
- struct adin1110_priv *priv = port_priv->priv;
- u32 header_len = ADIN1110_RD_HEADER_LEN;
- struct spi_transfer t = {0};
- u32 frame_size_no_fcs;
- struct sk_buff *rxb;
- u32 frame_size;
- int round_len;
- u16 reg;
- int ret;
- if (!port_priv->nr) {
- reg = ADIN1110_RX;
- ret = adin1110_read_reg(priv, ADIN1110_RX_FSIZE, &frame_size);
- } else {
- reg = ADIN2111_RX_P2;
- ret = adin1110_read_reg(priv, ADIN2111_RX_P2_FSIZE,
- &frame_size);
- }
- if (ret < 0)
- return ret;
- /* The read frame size includes the extra 2 bytes
- * from the ADIN1110 frame header.
- */
- if (frame_size < ADIN1110_FRAME_HEADER_LEN + ADIN1110_FEC_LEN)
- return ret;
- round_len = adin1110_round_len(frame_size);
- if (round_len < 0)
- return ret;
- frame_size_no_fcs = frame_size - ADIN1110_FRAME_HEADER_LEN - ADIN1110_FEC_LEN;
- memset(priv->data, 0, ADIN1110_RD_HEADER_LEN);
- priv->data[0] = ADIN1110_CD | FIELD_GET(GENMASK(12, 8), reg);
- priv->data[1] = FIELD_GET(GENMASK(7, 0), reg);
- if (priv->append_crc) {
- priv->data[2] = adin1110_crc_data(&priv->data[0], 2);
- header_len++;
- }
- rxb = netdev_alloc_skb(port_priv->netdev, round_len + header_len);
- if (!rxb)
- return -ENOMEM;
- skb_put(rxb, frame_size_no_fcs + header_len + ADIN1110_FRAME_HEADER_LEN);
- t.tx_buf = &priv->data[0];
- t.rx_buf = &rxb->data[0];
- t.len = header_len + round_len;
- ret = spi_sync_transfer(priv->spidev, &t, 1);
- if (ret) {
- kfree_skb(rxb);
- return ret;
- }
- skb_pull(rxb, header_len + ADIN1110_FRAME_HEADER_LEN);
- rxb->protocol = eth_type_trans(rxb, port_priv->netdev);
- if ((port_priv->flags & IFF_ALLMULTI && rxb->pkt_type == PACKET_MULTICAST) ||
- (port_priv->flags & IFF_BROADCAST && rxb->pkt_type == PACKET_BROADCAST))
- rxb->offload_fwd_mark = port_priv->priv->forwarding;
- netif_rx(rxb);
- port_priv->rx_bytes += frame_size - ADIN1110_FRAME_HEADER_LEN;
- port_priv->rx_packets++;
- return 0;
- }
- static int adin1110_write_fifo(struct adin1110_port_priv *port_priv,
- struct sk_buff *txb)
- {
- struct adin1110_priv *priv = port_priv->priv;
- u32 header_len = ADIN1110_WR_HEADER_LEN;
- __be16 frame_header;
- int padding = 0;
- int padded_len;
- int round_len;
- int ret;
- /* Pad frame to 64 byte length,
- * MAC nor PHY will otherwise add the
- * required padding.
- * The FEC will be added by the MAC internally.
- */
- if (txb->len + ADIN1110_FEC_LEN < 64)
- padding = 64 - (txb->len + ADIN1110_FEC_LEN);
- padded_len = txb->len + padding + ADIN1110_FRAME_HEADER_LEN;
- round_len = adin1110_round_len(padded_len);
- if (round_len < 0)
- return round_len;
- ret = adin1110_write_reg(priv, ADIN1110_TX_FSIZE, padded_len);
- if (ret < 0)
- return ret;
- memset(priv->data, 0, round_len + ADIN1110_WR_HEADER_LEN);
- priv->data[0] = ADIN1110_CD | ADIN1110_WRITE;
- priv->data[0] |= FIELD_GET(GENMASK(12, 8), ADIN1110_TX);
- priv->data[1] = FIELD_GET(GENMASK(7, 0), ADIN1110_TX);
- if (priv->append_crc) {
- priv->data[2] = adin1110_crc_data(&priv->data[0], 2);
- header_len++;
- }
- /* mention the port on which to send the frame in the frame header */
- frame_header = cpu_to_be16(port_priv->nr);
- memcpy(&priv->data[header_len], &frame_header,
- ADIN1110_FRAME_HEADER_LEN);
- memcpy(&priv->data[header_len + ADIN1110_FRAME_HEADER_LEN],
- txb->data, txb->len);
- ret = spi_write(priv->spidev, &priv->data[0], round_len + header_len);
- if (ret < 0)
- return ret;
- port_priv->tx_bytes += txb->len;
- port_priv->tx_packets++;
- return 0;
- }
- static int adin1110_read_mdio_acc(struct adin1110_priv *priv)
- {
- u32 val;
- int ret;
- mutex_lock(&priv->lock);
- ret = adin1110_read_reg(priv, ADIN1110_MDIOACC, &val);
- mutex_unlock(&priv->lock);
- if (ret < 0)
- return 0;
- return val;
- }
- static int adin1110_mdio_read(struct mii_bus *bus, int phy_id, int reg)
- {
- struct adin1110_priv *priv = bus->priv;
- u32 val = 0;
- int ret;
- if (mdio_phy_id_is_c45(phy_id))
- return -EOPNOTSUPP;
- val |= FIELD_PREP(ADIN1110_MDIO_OP, ADIN1110_MDIO_OP_RD);
- val |= FIELD_PREP(ADIN1110_MDIO_ST, 0x1);
- val |= FIELD_PREP(ADIN1110_MDIO_PRTAD, phy_id);
- val |= FIELD_PREP(ADIN1110_MDIO_DEVAD, reg);
- /* write the clause 22 read command to the chip */
- mutex_lock(&priv->lock);
- ret = adin1110_write_reg(priv, ADIN1110_MDIOACC, val);
- mutex_unlock(&priv->lock);
- if (ret < 0)
- return ret;
- /* ADIN1110_MDIO_TRDONE BIT of the ADIN1110_MDIOACC
- * register is set when the read is done.
- * After the transaction is done, ADIN1110_MDIO_DATA
- * bitfield of ADIN1110_MDIOACC register will contain
- * the requested register value.
- */
- ret = readx_poll_timeout(adin1110_read_mdio_acc, priv, val,
- (val & ADIN1110_MDIO_TRDONE), 10000, 30000);
- if (ret < 0)
- return ret;
- return (val & ADIN1110_MDIO_DATA);
- }
- static int adin1110_mdio_write(struct mii_bus *bus, int phy_id,
- int reg, u16 reg_val)
- {
- struct adin1110_priv *priv = bus->priv;
- u32 val = 0;
- int ret;
- if (mdio_phy_id_is_c45(phy_id))
- return -EOPNOTSUPP;
- val |= FIELD_PREP(ADIN1110_MDIO_OP, ADIN1110_MDIO_OP_WR);
- val |= FIELD_PREP(ADIN1110_MDIO_ST, 0x1);
- val |= FIELD_PREP(ADIN1110_MDIO_PRTAD, phy_id);
- val |= FIELD_PREP(ADIN1110_MDIO_DEVAD, reg);
- val |= FIELD_PREP(ADIN1110_MDIO_DATA, reg_val);
- /* write the clause 22 write command to the chip */
- mutex_lock(&priv->lock);
- ret = adin1110_write_reg(priv, ADIN1110_MDIOACC, val);
- mutex_unlock(&priv->lock);
- if (ret < 0)
- return ret;
- return readx_poll_timeout(adin1110_read_mdio_acc, priv, val,
- (val & ADIN1110_MDIO_TRDONE), 10000, 30000);
- }
- /* ADIN1110 MAC-PHY contains an ADIN1100 PHY.
- * ADIN2111 MAC-PHY contains two ADIN1100 PHYs.
- * By registering a new MDIO bus we allow the PAL to discover
- * the encapsulated PHY and probe the ADIN1100 driver.
- */
- static int adin1110_register_mdiobus(struct adin1110_priv *priv,
- struct device *dev)
- {
- struct mii_bus *mii_bus;
- int ret;
- mii_bus = devm_mdiobus_alloc(dev);
- if (!mii_bus)
- return -ENOMEM;
- snprintf(priv->mii_bus_name, MII_BUS_ID_SIZE, "%s-%u",
- priv->cfg->name, priv->spidev->chip_select);
- mii_bus->name = priv->mii_bus_name;
- mii_bus->read = adin1110_mdio_read;
- mii_bus->write = adin1110_mdio_write;
- mii_bus->priv = priv;
- mii_bus->parent = dev;
- mii_bus->phy_mask = ~((u32)GENMASK(2, 0));
- mii_bus->probe_capabilities = MDIOBUS_C22;
- snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev));
- ret = devm_mdiobus_register(dev, mii_bus);
- if (ret)
- return ret;
- priv->mii_bus = mii_bus;
- return 0;
- }
- static bool adin1110_port_rx_ready(struct adin1110_port_priv *port_priv,
- u32 status)
- {
- if (!netif_oper_up(port_priv->netdev))
- return false;
- if (!port_priv->nr)
- return !!(status & ADIN1110_RX_RDY);
- else
- return !!(status & ADIN2111_P2_RX_RDY);
- }
- static void adin1110_read_frames(struct adin1110_port_priv *port_priv,
- unsigned int budget)
- {
- struct adin1110_priv *priv = port_priv->priv;
- u32 status1;
- int ret;
- while (budget) {
- ret = adin1110_read_reg(priv, ADIN1110_STATUS1, &status1);
- if (ret < 0)
- return;
- if (!adin1110_port_rx_ready(port_priv, status1))
- break;
- ret = adin1110_read_fifo(port_priv);
- if (ret < 0)
- return;
- budget--;
- }
- }
- static void adin1110_wake_queues(struct adin1110_priv *priv)
- {
- int i;
- for (i = 0; i < priv->cfg->ports_nr; i++)
- netif_wake_queue(priv->ports[i]->netdev);
- }
- static irqreturn_t adin1110_irq(int irq, void *p)
- {
- struct adin1110_priv *priv = p;
- u32 status1;
- u32 val;
- int ret;
- int i;
- mutex_lock(&priv->lock);
- ret = adin1110_read_reg(priv, ADIN1110_STATUS1, &status1);
- if (ret < 0)
- goto out;
- if (priv->append_crc && (status1 & ADIN1110_SPI_ERR))
- dev_warn_ratelimited(&priv->spidev->dev,
- "SPI CRC error on write.\n");
- ret = adin1110_read_reg(priv, ADIN1110_TX_SPACE, &val);
- if (ret < 0)
- goto out;
- /* TX FIFO space is expressed in half-words */
- priv->tx_space = 2 * val;
- for (i = 0; i < priv->cfg->ports_nr; i++) {
- if (adin1110_port_rx_ready(priv->ports[i], status1))
- adin1110_read_frames(priv->ports[i],
- ADIN1110_MAX_FRAMES_READ);
- }
- /* clear IRQ sources */
- adin1110_write_reg(priv, ADIN1110_STATUS0, ADIN1110_CLEAR_STATUS0);
- adin1110_write_reg(priv, ADIN1110_STATUS1, priv->irq_mask);
- out:
- mutex_unlock(&priv->lock);
- if (priv->tx_space > 0 && ret >= 0)
- adin1110_wake_queues(priv);
- return IRQ_HANDLED;
- }
- /* ADIN1110 can filter up to 16 MAC addresses, mac_nr here is the slot used */
- static int adin1110_write_mac_address(struct adin1110_port_priv *port_priv,
- int mac_nr, const u8 *addr,
- u8 *mask, u32 port_rules)
- {
- struct adin1110_priv *priv = port_priv->priv;
- u32 offset = mac_nr * 2;
- u32 port_rules_mask;
- int ret;
- u32 val;
- if (!port_priv->nr)
- port_rules_mask = ADIN1110_MAC_ADDR_APPLY2PORT;
- else
- port_rules_mask = ADIN2111_MAC_ADDR_APPLY2PORT2;
- if (port_rules & port_rules_mask)
- port_rules_mask |= ADIN1110_MAC_ADDR_TO_HOST | ADIN2111_MAC_ADDR_TO_OTHER_PORT;
- port_rules_mask |= GENMASK(15, 0);
- val = port_rules | get_unaligned_be16(&addr[0]);
- ret = adin1110_set_bits(priv, ADIN1110_MAC_ADDR_FILTER_UPR + offset,
- port_rules_mask, val);
- if (ret < 0)
- return ret;
- val = get_unaligned_be32(&addr[2]);
- ret = adin1110_write_reg(priv,
- ADIN1110_MAC_ADDR_FILTER_LWR + offset, val);
- if (ret < 0)
- return ret;
- /* Only the first two MAC address slots support masking. */
- if (mac_nr < ADIN_MAC_P1_ADDR_SLOT) {
- val = get_unaligned_be16(&mask[0]);
- ret = adin1110_write_reg(priv,
- ADIN1110_MAC_ADDR_MASK_UPR + offset,
- val);
- if (ret < 0)
- return ret;
- val = get_unaligned_be32(&mask[2]);
- return adin1110_write_reg(priv,
- ADIN1110_MAC_ADDR_MASK_LWR + offset,
- val);
- }
- return 0;
- }
- static int adin1110_clear_mac_address(struct adin1110_priv *priv, int mac_nr)
- {
- u32 offset = mac_nr * 2;
- int ret;
- ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_FILTER_UPR + offset, 0);
- if (ret < 0)
- return ret;
- ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_FILTER_LWR + offset, 0);
- if (ret < 0)
- return ret;
- /* only the first two MAC address slots are maskable */
- if (mac_nr <= 1) {
- ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_UPR + offset, 0);
- if (ret < 0)
- return ret;
- ret = adin1110_write_reg(priv, ADIN1110_MAC_ADDR_MASK_LWR + offset, 0);
- }
- return ret;
- }
- static u32 adin1110_port_rules(struct adin1110_port_priv *port_priv,
- bool fw_to_host,
- bool fw_to_other_port)
- {
- u32 port_rules = 0;
- if (!port_priv->nr)
- port_rules |= ADIN1110_MAC_ADDR_APPLY2PORT;
- else
- port_rules |= ADIN2111_MAC_ADDR_APPLY2PORT2;
- if (fw_to_host)
- port_rules |= ADIN1110_MAC_ADDR_TO_HOST;
- if (fw_to_other_port && port_priv->priv->forwarding)
- port_rules |= ADIN2111_MAC_ADDR_TO_OTHER_PORT;
- return port_rules;
- }
- static int adin1110_multicast_filter(struct adin1110_port_priv *port_priv,
- int mac_nr, bool accept_multicast)
- {
- u8 mask[ETH_ALEN] = {0};
- u8 mac[ETH_ALEN] = {0};
- u32 port_rules = 0;
- mask[0] = BIT(0);
- mac[0] = BIT(0);
- if (accept_multicast && port_priv->state == BR_STATE_FORWARDING)
- port_rules = adin1110_port_rules(port_priv, true, true);
- return adin1110_write_mac_address(port_priv, mac_nr, mac,
- mask, port_rules);
- }
- static int adin1110_broadcasts_filter(struct adin1110_port_priv *port_priv,
- int mac_nr, bool accept_broadcast)
- {
- u32 port_rules = 0;
- u8 mask[ETH_ALEN];
- eth_broadcast_addr(mask);
- if (accept_broadcast && port_priv->state == BR_STATE_FORWARDING)
- port_rules = adin1110_port_rules(port_priv, true, true);
- return adin1110_write_mac_address(port_priv, mac_nr, mask,
- mask, port_rules);
- }
- static int adin1110_set_mac_address(struct net_device *netdev,
- const unsigned char *dev_addr)
- {
- struct adin1110_port_priv *port_priv = netdev_priv(netdev);
- u8 mask[ETH_ALEN];
- u32 port_rules;
- u32 mac_slot;
- if (!is_valid_ether_addr(dev_addr))
- return -EADDRNOTAVAIL;
- eth_hw_addr_set(netdev, dev_addr);
- eth_broadcast_addr(mask);
- mac_slot = (!port_priv->nr) ? ADIN_MAC_P1_ADDR_SLOT : ADIN_MAC_P2_ADDR_SLOT;
- port_rules = adin1110_port_rules(port_priv, true, false);
- return adin1110_write_mac_address(port_priv, mac_slot, netdev->dev_addr,
- mask, port_rules);
- }
- static int adin1110_ndo_set_mac_address(struct net_device *netdev, void *addr)
- {
- struct sockaddr *sa = addr;
- int ret;
- ret = eth_prepare_mac_addr_change(netdev, addr);
- if (ret < 0)
- return ret;
- return adin1110_set_mac_address(netdev, sa->sa_data);
- }
- static int adin1110_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
- {
- if (!netif_running(netdev))
- return -EINVAL;
- return phy_do_ioctl(netdev, rq, cmd);
- }
- static int adin1110_set_promisc_mode(struct adin1110_port_priv *port_priv,
- bool promisc)
- {
- struct adin1110_priv *priv = port_priv->priv;
- u32 mask;
- if (port_priv->state != BR_STATE_FORWARDING)
- promisc = false;
- if (!port_priv->nr)
- mask = ADIN1110_FWD_UNK2HOST;
- else
- mask = ADIN2111_P2_FWD_UNK2HOST;
- return adin1110_set_bits(priv, ADIN1110_CONFIG2,
- mask, promisc ? mask : 0);
- }
- static int adin1110_setup_rx_mode(struct adin1110_port_priv *port_priv)
- {
- int ret;
- ret = adin1110_set_promisc_mode(port_priv,
- !!(port_priv->flags & IFF_PROMISC));
- if (ret < 0)
- return ret;
- ret = adin1110_multicast_filter(port_priv, ADIN_MAC_MULTICAST_ADDR_SLOT,
- !!(port_priv->flags & IFF_ALLMULTI));
- if (ret < 0)
- return ret;
- ret = adin1110_broadcasts_filter(port_priv,
- ADIN_MAC_BROADCAST_ADDR_SLOT,
- !!(port_priv->flags & IFF_BROADCAST));
- if (ret < 0)
- return ret;
- return adin1110_set_bits(port_priv->priv, ADIN1110_CONFIG1,
- ADIN1110_CONFIG1_SYNC, ADIN1110_CONFIG1_SYNC);
- }
- static bool adin1110_can_offload_forwarding(struct adin1110_priv *priv)
- {
- int i;
- if (priv->cfg->id != ADIN2111_MAC)
- return false;
- /* Can't enable forwarding if ports do not belong to the same bridge */
- if (priv->ports[0]->bridge != priv->ports[1]->bridge || !priv->ports[0]->bridge)
- return false;
- /* Can't enable forwarding if there is a port
- * that has been blocked by STP.
- */
- for (i = 0; i < priv->cfg->ports_nr; i++) {
- if (priv->ports[i]->state != BR_STATE_FORWARDING)
- return false;
- }
- return true;
- }
- static void adin1110_rx_mode_work(struct work_struct *work)
- {
- struct adin1110_port_priv *port_priv;
- struct adin1110_priv *priv;
- port_priv = container_of(work, struct adin1110_port_priv, rx_mode_work);
- priv = port_priv->priv;
- mutex_lock(&priv->lock);
- adin1110_setup_rx_mode(port_priv);
- mutex_unlock(&priv->lock);
- }
- static void adin1110_set_rx_mode(struct net_device *dev)
- {
- struct adin1110_port_priv *port_priv = netdev_priv(dev);
- struct adin1110_priv *priv = port_priv->priv;
- spin_lock(&priv->state_lock);
- port_priv->flags = dev->flags;
- schedule_work(&port_priv->rx_mode_work);
- spin_unlock(&priv->state_lock);
- }
- static int adin1110_net_open(struct net_device *net_dev)
- {
- struct adin1110_port_priv *port_priv = netdev_priv(net_dev);
- struct adin1110_priv *priv = port_priv->priv;
- u32 val;
- int ret;
- mutex_lock(&priv->lock);
- /* Configure MAC to compute and append the FCS itself. */
- ret = adin1110_write_reg(priv, ADIN1110_CONFIG2, ADIN1110_CRC_APPEND);
- if (ret < 0)
- goto out;
- val = ADIN1110_TX_RDY_IRQ | ADIN1110_RX_RDY_IRQ | ADIN1110_SPI_ERR_IRQ;
- if (priv->cfg->id == ADIN2111_MAC)
- val |= ADIN2111_RX_RDY_IRQ;
- priv->irq_mask = val;
- ret = adin1110_write_reg(priv, ADIN1110_IMASK1, ~val);
- if (ret < 0) {
- netdev_err(net_dev, "Failed to enable chip IRQs: %d\n", ret);
- goto out;
- }
- ret = adin1110_read_reg(priv, ADIN1110_TX_SPACE, &val);
- if (ret < 0) {
- netdev_err(net_dev, "Failed to read TX FIFO space: %d\n", ret);
- goto out;
- }
- priv->tx_space = 2 * val;
- port_priv->state = BR_STATE_FORWARDING;
- ret = adin1110_set_mac_address(net_dev, net_dev->dev_addr);
- if (ret < 0) {
- netdev_err(net_dev, "Could not set MAC address: %pM, %d\n",
- net_dev->dev_addr, ret);
- goto out;
- }
- ret = adin1110_set_bits(priv, ADIN1110_CONFIG1, ADIN1110_CONFIG1_SYNC,
- ADIN1110_CONFIG1_SYNC);
- out:
- mutex_unlock(&priv->lock);
- if (ret < 0)
- return ret;
- phy_start(port_priv->phydev);
- netif_start_queue(net_dev);
- return 0;
- }
- static int adin1110_net_stop(struct net_device *net_dev)
- {
- struct adin1110_port_priv *port_priv = netdev_priv(net_dev);
- struct adin1110_priv *priv = port_priv->priv;
- u32 mask;
- int ret;
- mask = !port_priv->nr ? ADIN2111_RX_RDY_IRQ : ADIN1110_RX_RDY_IRQ;
- /* Disable RX RDY IRQs */
- mutex_lock(&priv->lock);
- ret = adin1110_set_bits(priv, ADIN1110_IMASK1, mask, mask);
- mutex_unlock(&priv->lock);
- if (ret < 0)
- return ret;
- netif_stop_queue(port_priv->netdev);
- flush_work(&port_priv->tx_work);
- phy_stop(port_priv->phydev);
- return 0;
- }
- static void adin1110_tx_work(struct work_struct *work)
- {
- struct adin1110_port_priv *port_priv;
- struct adin1110_priv *priv;
- struct sk_buff *txb;
- int ret;
- port_priv = container_of(work, struct adin1110_port_priv, tx_work);
- priv = port_priv->priv;
- mutex_lock(&priv->lock);
- while ((txb = skb_dequeue(&port_priv->txq))) {
- ret = adin1110_write_fifo(port_priv, txb);
- if (ret < 0)
- dev_err_ratelimited(&priv->spidev->dev,
- "Frame write error: %d\n", ret);
- dev_kfree_skb(txb);
- }
- mutex_unlock(&priv->lock);
- }
- static netdev_tx_t adin1110_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- struct adin1110_port_priv *port_priv = netdev_priv(dev);
- struct adin1110_priv *priv = port_priv->priv;
- netdev_tx_t netdev_ret = NETDEV_TX_OK;
- u32 tx_space_needed;
- tx_space_needed = skb->len + ADIN1110_FRAME_HEADER_LEN + ADIN1110_INTERNAL_SIZE_HEADER_LEN;
- if (tx_space_needed > priv->tx_space) {
- netif_stop_queue(dev);
- netdev_ret = NETDEV_TX_BUSY;
- } else {
- priv->tx_space -= tx_space_needed;
- skb_queue_tail(&port_priv->txq, skb);
- }
- schedule_work(&port_priv->tx_work);
- return netdev_ret;
- }
- static void adin1110_ndo_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *storage)
- {
- struct adin1110_port_priv *port_priv = netdev_priv(dev);
- storage->rx_packets = port_priv->rx_packets;
- storage->tx_packets = port_priv->tx_packets;
- storage->rx_bytes = port_priv->rx_bytes;
- storage->tx_bytes = port_priv->tx_bytes;
- }
- static int adin1110_port_get_port_parent_id(struct net_device *dev,
- struct netdev_phys_item_id *ppid)
- {
- struct adin1110_port_priv *port_priv = netdev_priv(dev);
- struct adin1110_priv *priv = port_priv->priv;
- ppid->id_len = strnlen(priv->mii_bus_name, MAX_PHYS_ITEM_ID_LEN);
- memcpy(ppid->id, priv->mii_bus_name, ppid->id_len);
- return 0;
- }
- static int adin1110_ndo_get_phys_port_name(struct net_device *dev,
- char *name, size_t len)
- {
- struct adin1110_port_priv *port_priv = netdev_priv(dev);
- int err;
- err = snprintf(name, len, "p%d", port_priv->nr);
- if (err >= len)
- return -EINVAL;
- return 0;
- }
- static const struct net_device_ops adin1110_netdev_ops = {
- .ndo_open = adin1110_net_open,
- .ndo_stop = adin1110_net_stop,
- .ndo_eth_ioctl = adin1110_ioctl,
- .ndo_start_xmit = adin1110_start_xmit,
- .ndo_set_mac_address = adin1110_ndo_set_mac_address,
- .ndo_set_rx_mode = adin1110_set_rx_mode,
- .ndo_validate_addr = eth_validate_addr,
- .ndo_get_stats64 = adin1110_ndo_get_stats64,
- .ndo_get_port_parent_id = adin1110_port_get_port_parent_id,
- .ndo_get_phys_port_name = adin1110_ndo_get_phys_port_name,
- };
- static void adin1110_get_drvinfo(struct net_device *dev,
- struct ethtool_drvinfo *di)
- {
- strscpy(di->driver, "ADIN1110", sizeof(di->driver));
- strscpy(di->bus_info, dev_name(dev->dev.parent), sizeof(di->bus_info));
- }
- static const struct ethtool_ops adin1110_ethtool_ops = {
- .get_drvinfo = adin1110_get_drvinfo,
- .get_link = ethtool_op_get_link,
- .get_link_ksettings = phy_ethtool_get_link_ksettings,
- .set_link_ksettings = phy_ethtool_set_link_ksettings,
- };
- static void adin1110_adjust_link(struct net_device *dev)
- {
- struct phy_device *phydev = dev->phydev;
- if (!phydev->link)
- phy_print_status(phydev);
- }
- /* PHY ID is stored in the MAC registers too,
- * check spi connection by reading it.
- */
- static int adin1110_check_spi(struct adin1110_priv *priv)
- {
- int ret;
- u32 val;
- ret = adin1110_read_reg(priv, ADIN1110_PHY_ID, &val);
- if (ret < 0)
- return ret;
- if (val != priv->cfg->phy_id_val) {
- dev_err(&priv->spidev->dev, "PHY ID expected: %x, read: %x\n",
- priv->cfg->phy_id_val, val);
- return -EIO;
- }
- return 0;
- }
- static int adin1110_hw_forwarding(struct adin1110_priv *priv, bool enable)
- {
- int ret;
- int i;
- priv->forwarding = enable;
- if (!priv->forwarding) {
- for (i = ADIN_MAC_FDB_ADDR_SLOT; i < ADIN_MAC_MAX_ADDR_SLOTS; i++) {
- ret = adin1110_clear_mac_address(priv, i);
- if (ret < 0)
- return ret;
- }
- }
- /* Forwarding is optimised when MAC runs in Cut Through mode. */
- ret = adin1110_set_bits(priv, ADIN1110_CONFIG2,
- ADIN2111_PORT_CUT_THRU_EN,
- priv->forwarding ? ADIN2111_PORT_CUT_THRU_EN : 0);
- if (ret < 0)
- return ret;
- for (i = 0; i < priv->cfg->ports_nr; i++) {
- ret = adin1110_setup_rx_mode(priv->ports[i]);
- if (ret < 0)
- return ret;
- }
- return ret;
- }
- static int adin1110_port_bridge_join(struct adin1110_port_priv *port_priv,
- struct net_device *bridge)
- {
- struct adin1110_priv *priv = port_priv->priv;
- int ret;
- port_priv->bridge = bridge;
- if (adin1110_can_offload_forwarding(priv)) {
- mutex_lock(&priv->lock);
- ret = adin1110_hw_forwarding(priv, true);
- mutex_unlock(&priv->lock);
- if (ret < 0)
- return ret;
- }
- return adin1110_set_mac_address(port_priv->netdev, bridge->dev_addr);
- }
- static int adin1110_port_bridge_leave(struct adin1110_port_priv *port_priv,
- struct net_device *bridge)
- {
- struct adin1110_priv *priv = port_priv->priv;
- int ret;
- port_priv->bridge = NULL;
- mutex_lock(&priv->lock);
- ret = adin1110_hw_forwarding(priv, false);
- mutex_unlock(&priv->lock);
- return ret;
- }
- static bool adin1110_port_dev_check(const struct net_device *dev)
- {
- return dev->netdev_ops == &adin1110_netdev_ops;
- }
- static int adin1110_netdevice_event(struct notifier_block *unused,
- unsigned long event, void *ptr)
- {
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
- struct adin1110_port_priv *port_priv = netdev_priv(dev);
- struct netdev_notifier_changeupper_info *info = ptr;
- int ret = 0;
- if (!adin1110_port_dev_check(dev))
- return NOTIFY_DONE;
- switch (event) {
- case NETDEV_CHANGEUPPER:
- if (netif_is_bridge_master(info->upper_dev)) {
- if (info->linking)
- ret = adin1110_port_bridge_join(port_priv, info->upper_dev);
- else
- ret = adin1110_port_bridge_leave(port_priv, info->upper_dev);
- }
- break;
- default:
- break;
- }
- return notifier_from_errno(ret);
- }
- static struct notifier_block adin1110_netdevice_nb = {
- .notifier_call = adin1110_netdevice_event,
- };
- static void adin1110_disconnect_phy(void *data)
- {
- phy_disconnect(data);
- }
- static int adin1110_port_set_forwarding_state(struct adin1110_port_priv *port_priv)
- {
- struct adin1110_priv *priv = port_priv->priv;
- int ret;
- port_priv->state = BR_STATE_FORWARDING;
- mutex_lock(&priv->lock);
- ret = adin1110_set_mac_address(port_priv->netdev,
- port_priv->netdev->dev_addr);
- if (ret < 0)
- goto out;
- if (adin1110_can_offload_forwarding(priv))
- ret = adin1110_hw_forwarding(priv, true);
- else
- ret = adin1110_setup_rx_mode(port_priv);
- out:
- mutex_unlock(&priv->lock);
- return ret;
- }
- static int adin1110_port_set_blocking_state(struct adin1110_port_priv *port_priv)
- {
- u8 mac[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00};
- struct adin1110_priv *priv = port_priv->priv;
- u8 mask[ETH_ALEN];
- u32 port_rules;
- int mac_slot;
- int ret;
- port_priv->state = BR_STATE_BLOCKING;
- mutex_lock(&priv->lock);
- mac_slot = (!port_priv->nr) ? ADIN_MAC_P1_ADDR_SLOT : ADIN_MAC_P2_ADDR_SLOT;
- ret = adin1110_clear_mac_address(priv, mac_slot);
- if (ret < 0)
- goto out;
- ret = adin1110_hw_forwarding(priv, false);
- if (ret < 0)
- goto out;
- /* Allow only BPDUs to be passed to the CPU */
- eth_broadcast_addr(mask);
- port_rules = adin1110_port_rules(port_priv, true, false);
- ret = adin1110_write_mac_address(port_priv, mac_slot, mac,
- mask, port_rules);
- out:
- mutex_unlock(&priv->lock);
- return ret;
- }
- /* ADIN1110/2111 does not have any native STP support.
- * Listen for bridge core state changes and
- * allow all frames to pass or only the BPDUs.
- */
- static int adin1110_port_attr_stp_state_set(struct adin1110_port_priv *port_priv,
- u8 state)
- {
- switch (state) {
- case BR_STATE_FORWARDING:
- return adin1110_port_set_forwarding_state(port_priv);
- case BR_STATE_LEARNING:
- case BR_STATE_LISTENING:
- case BR_STATE_DISABLED:
- case BR_STATE_BLOCKING:
- return adin1110_port_set_blocking_state(port_priv);
- default:
- return -EINVAL;
- }
- }
- static int adin1110_port_attr_set(struct net_device *dev, const void *ctx,
- const struct switchdev_attr *attr,
- struct netlink_ext_ack *extack)
- {
- struct adin1110_port_priv *port_priv = netdev_priv(dev);
- switch (attr->id) {
- case SWITCHDEV_ATTR_ID_PORT_STP_STATE:
- return adin1110_port_attr_stp_state_set(port_priv,
- attr->u.stp_state);
- default:
- return -EOPNOTSUPP;
- }
- }
- static int adin1110_switchdev_blocking_event(struct notifier_block *unused,
- unsigned long event,
- void *ptr)
- {
- struct net_device *netdev = switchdev_notifier_info_to_dev(ptr);
- int ret;
- if (event == SWITCHDEV_PORT_ATTR_SET) {
- ret = switchdev_handle_port_attr_set(netdev, ptr,
- adin1110_port_dev_check,
- adin1110_port_attr_set);
- return notifier_from_errno(ret);
- }
- return NOTIFY_DONE;
- }
- static struct notifier_block adin1110_switchdev_blocking_notifier = {
- .notifier_call = adin1110_switchdev_blocking_event,
- };
- static void adin1110_fdb_offload_notify(struct net_device *netdev,
- struct switchdev_notifier_fdb_info *rcv)
- {
- struct switchdev_notifier_fdb_info info = {};
- info.addr = rcv->addr;
- info.vid = rcv->vid;
- info.offloaded = true;
- call_switchdev_notifiers(SWITCHDEV_FDB_OFFLOADED,
- netdev, &info.info, NULL);
- }
- static int adin1110_fdb_add(struct adin1110_port_priv *port_priv,
- struct switchdev_notifier_fdb_info *fdb)
- {
- struct adin1110_priv *priv = port_priv->priv;
- struct adin1110_port_priv *other_port;
- u8 mask[ETH_ALEN];
- u32 port_rules;
- int mac_nr;
- u32 val;
- int ret;
- netdev_dbg(port_priv->netdev,
- "DEBUG: %s: MACID = %pM vid = %u flags = %u %u -- port %d\n",
- __func__, fdb->addr, fdb->vid, fdb->added_by_user,
- fdb->offloaded, port_priv->nr);
- if (!priv->forwarding)
- return 0;
- if (fdb->is_local)
- return -EINVAL;
- /* Find free FDB slot on device. */
- for (mac_nr = ADIN_MAC_FDB_ADDR_SLOT; mac_nr < ADIN_MAC_MAX_ADDR_SLOTS; mac_nr++) {
- ret = adin1110_read_reg(priv, ADIN1110_MAC_ADDR_FILTER_UPR + (mac_nr * 2), &val);
- if (ret < 0)
- return ret;
- if (!val)
- break;
- }
- if (mac_nr == ADIN_MAC_MAX_ADDR_SLOTS)
- return -ENOMEM;
- other_port = priv->ports[!port_priv->nr];
- port_rules = adin1110_port_rules(other_port, false, true);
- eth_broadcast_addr(mask);
- return adin1110_write_mac_address(other_port, mac_nr, (u8 *)fdb->addr,
- mask, port_rules);
- }
- static int adin1110_read_mac(struct adin1110_priv *priv, int mac_nr, u8 *addr)
- {
- u32 val;
- int ret;
- ret = adin1110_read_reg(priv, ADIN1110_MAC_ADDR_FILTER_UPR + (mac_nr * 2), &val);
- if (ret < 0)
- return ret;
- put_unaligned_be16(val, addr);
- ret = adin1110_read_reg(priv, ADIN1110_MAC_ADDR_FILTER_LWR + (mac_nr * 2), &val);
- if (ret < 0)
- return ret;
- put_unaligned_be32(val, addr + 2);
- return 0;
- }
- static int adin1110_fdb_del(struct adin1110_port_priv *port_priv,
- struct switchdev_notifier_fdb_info *fdb)
- {
- struct adin1110_priv *priv = port_priv->priv;
- u8 addr[ETH_ALEN];
- int mac_nr;
- int ret;
- netdev_dbg(port_priv->netdev,
- "DEBUG: %s: MACID = %pM vid = %u flags = %u %u -- port %d\n",
- __func__, fdb->addr, fdb->vid, fdb->added_by_user,
- fdb->offloaded, port_priv->nr);
- if (fdb->is_local)
- return -EINVAL;
- for (mac_nr = ADIN_MAC_FDB_ADDR_SLOT; mac_nr < ADIN_MAC_MAX_ADDR_SLOTS; mac_nr++) {
- ret = adin1110_read_mac(priv, mac_nr, addr);
- if (ret < 0)
- return ret;
- if (ether_addr_equal(addr, fdb->addr)) {
- ret = adin1110_clear_mac_address(priv, mac_nr);
- if (ret < 0)
- return ret;
- }
- }
- return 0;
- }
- static void adin1110_switchdev_event_work(struct work_struct *work)
- {
- struct adin1110_switchdev_event_work *switchdev_work;
- struct adin1110_port_priv *port_priv;
- int ret;
- switchdev_work = container_of(work, struct adin1110_switchdev_event_work, work);
- port_priv = switchdev_work->port_priv;
- mutex_lock(&port_priv->priv->lock);
- switch (switchdev_work->event) {
- case SWITCHDEV_FDB_ADD_TO_DEVICE:
- ret = adin1110_fdb_add(port_priv, &switchdev_work->fdb_info);
- if (!ret)
- adin1110_fdb_offload_notify(port_priv->netdev,
- &switchdev_work->fdb_info);
- break;
- case SWITCHDEV_FDB_DEL_TO_DEVICE:
- adin1110_fdb_del(port_priv, &switchdev_work->fdb_info);
- break;
- default:
- break;
- }
- mutex_unlock(&port_priv->priv->lock);
- kfree(switchdev_work->fdb_info.addr);
- kfree(switchdev_work);
- dev_put(port_priv->netdev);
- }
- /* called under rcu_read_lock() */
- static int adin1110_switchdev_event(struct notifier_block *unused,
- unsigned long event, void *ptr)
- {
- struct net_device *netdev = switchdev_notifier_info_to_dev(ptr);
- struct adin1110_port_priv *port_priv = netdev_priv(netdev);
- struct adin1110_switchdev_event_work *switchdev_work;
- struct switchdev_notifier_fdb_info *fdb_info = ptr;
- if (!adin1110_port_dev_check(netdev))
- return NOTIFY_DONE;
- switchdev_work = kzalloc(sizeof(*switchdev_work), GFP_ATOMIC);
- if (WARN_ON(!switchdev_work))
- return NOTIFY_BAD;
- INIT_WORK(&switchdev_work->work, adin1110_switchdev_event_work);
- switchdev_work->port_priv = port_priv;
- switchdev_work->event = event;
- switch (event) {
- case SWITCHDEV_FDB_ADD_TO_DEVICE:
- case SWITCHDEV_FDB_DEL_TO_DEVICE:
- memcpy(&switchdev_work->fdb_info, ptr,
- sizeof(switchdev_work->fdb_info));
- switchdev_work->fdb_info.addr = kzalloc(ETH_ALEN, GFP_ATOMIC);
- if (!switchdev_work->fdb_info.addr)
- goto err_addr_alloc;
- ether_addr_copy((u8 *)switchdev_work->fdb_info.addr,
- fdb_info->addr);
- dev_hold(netdev);
- break;
- default:
- kfree(switchdev_work);
- return NOTIFY_DONE;
- }
- queue_work(system_long_wq, &switchdev_work->work);
- return NOTIFY_DONE;
- err_addr_alloc:
- kfree(switchdev_work);
- return NOTIFY_BAD;
- }
- static struct notifier_block adin1110_switchdev_notifier = {
- .notifier_call = adin1110_switchdev_event,
- };
- static void adin1110_unregister_notifiers(void)
- {
- unregister_switchdev_blocking_notifier(&adin1110_switchdev_blocking_notifier);
- unregister_switchdev_notifier(&adin1110_switchdev_notifier);
- unregister_netdevice_notifier(&adin1110_netdevice_nb);
- }
- static int adin1110_setup_notifiers(void)
- {
- int ret;
- ret = register_netdevice_notifier(&adin1110_netdevice_nb);
- if (ret < 0)
- return ret;
- ret = register_switchdev_notifier(&adin1110_switchdev_notifier);
- if (ret < 0)
- goto err_netdev;
- ret = register_switchdev_blocking_notifier(&adin1110_switchdev_blocking_notifier);
- if (ret < 0)
- goto err_sdev;
- return 0;
- err_sdev:
- unregister_switchdev_notifier(&adin1110_switchdev_notifier);
- err_netdev:
- unregister_netdevice_notifier(&adin1110_netdevice_nb);
- return ret;
- }
- static int adin1110_probe_netdevs(struct adin1110_priv *priv)
- {
- struct device *dev = &priv->spidev->dev;
- struct adin1110_port_priv *port_priv;
- struct net_device *netdev;
- int ret;
- int i;
- for (i = 0; i < priv->cfg->ports_nr; i++) {
- netdev = devm_alloc_etherdev(dev, sizeof(*port_priv));
- if (!netdev)
- return -ENOMEM;
- port_priv = netdev_priv(netdev);
- port_priv->netdev = netdev;
- port_priv->priv = priv;
- port_priv->cfg = priv->cfg;
- port_priv->nr = i;
- priv->ports[i] = port_priv;
- SET_NETDEV_DEV(netdev, dev);
- ret = device_get_ethdev_address(dev, netdev);
- if (ret < 0)
- return ret;
- netdev->irq = priv->spidev->irq;
- INIT_WORK(&port_priv->tx_work, adin1110_tx_work);
- INIT_WORK(&port_priv->rx_mode_work, adin1110_rx_mode_work);
- skb_queue_head_init(&port_priv->txq);
- netif_carrier_off(netdev);
- netdev->if_port = IF_PORT_10BASET;
- netdev->netdev_ops = &adin1110_netdev_ops;
- netdev->ethtool_ops = &adin1110_ethtool_ops;
- netdev->priv_flags |= IFF_UNICAST_FLT;
- netdev->features |= NETIF_F_NETNS_LOCAL;
- port_priv->phydev = get_phy_device(priv->mii_bus, i + 1, false);
- if (IS_ERR(port_priv->phydev)) {
- netdev_err(netdev, "Could not find PHY with device address: %d.\n", i);
- return PTR_ERR(port_priv->phydev);
- }
- port_priv->phydev = phy_connect(netdev,
- phydev_name(port_priv->phydev),
- adin1110_adjust_link,
- PHY_INTERFACE_MODE_INTERNAL);
- if (IS_ERR(port_priv->phydev)) {
- netdev_err(netdev, "Could not connect PHY with device address: %d.\n", i);
- return PTR_ERR(port_priv->phydev);
- }
- ret = devm_add_action_or_reset(dev, adin1110_disconnect_phy,
- port_priv->phydev);
- if (ret < 0)
- return ret;
- }
- /* ADIN1110 INT_N pin will be used to signal the host */
- ret = devm_request_threaded_irq(dev, priv->spidev->irq, NULL,
- adin1110_irq,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- dev_name(dev), priv);
- if (ret < 0)
- return ret;
- for (i = 0; i < priv->cfg->ports_nr; i++) {
- ret = devm_register_netdev(dev, priv->ports[i]->netdev);
- if (ret < 0) {
- dev_err(dev, "Failed to register network device.\n");
- return ret;
- }
- }
- return 0;
- }
- static int adin1110_probe(struct spi_device *spi)
- {
- const struct spi_device_id *dev_id = spi_get_device_id(spi);
- struct device *dev = &spi->dev;
- struct adin1110_priv *priv;
- int ret;
- priv = devm_kzalloc(dev, sizeof(struct adin1110_priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- priv->spidev = spi;
- priv->cfg = &adin1110_cfgs[dev_id->driver_data];
- spi->bits_per_word = 8;
- spi->mode = SPI_MODE_0;
- mutex_init(&priv->lock);
- spin_lock_init(&priv->state_lock);
- /* use of CRC on control and data transactions is pin dependent */
- priv->append_crc = device_property_read_bool(dev, "adi,spi-crc");
- if (priv->append_crc)
- crc8_populate_msb(adin1110_crc_table, 0x7);
- ret = adin1110_check_spi(priv);
- if (ret < 0) {
- dev_err(dev, "Probe SPI Read check failed: %d\n", ret);
- return ret;
- }
- ret = adin1110_write_reg(priv, ADIN1110_RESET, ADIN1110_SWRESET);
- if (ret < 0)
- return ret;
- ret = adin1110_register_mdiobus(priv, dev);
- if (ret < 0) {
- dev_err(dev, "Could not register MDIO bus %d\n", ret);
- return ret;
- }
- return adin1110_probe_netdevs(priv);
- }
- static const struct of_device_id adin1110_match_table[] = {
- { .compatible = "adi,adin1110" },
- { .compatible = "adi,adin2111" },
- { }
- };
- MODULE_DEVICE_TABLE(of, adin1110_match_table);
- static const struct spi_device_id adin1110_spi_id[] = {
- { .name = "adin1110", .driver_data = ADIN1110_MAC },
- { .name = "adin2111", .driver_data = ADIN2111_MAC },
- { }
- };
- MODULE_DEVICE_TABLE(spi, adin1110_spi_id);
- static struct spi_driver adin1110_driver = {
- .driver = {
- .name = "adin1110",
- .of_match_table = adin1110_match_table,
- },
- .probe = adin1110_probe,
- .id_table = adin1110_spi_id,
- };
- static int __init adin1110_driver_init(void)
- {
- int ret;
- ret = adin1110_setup_notifiers();
- if (ret < 0)
- return ret;
- ret = spi_register_driver(&adin1110_driver);
- if (ret < 0) {
- adin1110_unregister_notifiers();
- return ret;
- }
- return 0;
- }
- static void __exit adin1110_exit(void)
- {
- adin1110_unregister_notifiers();
- spi_unregister_driver(&adin1110_driver);
- }
- module_init(adin1110_driver_init);
- module_exit(adin1110_exit);
- MODULE_DESCRIPTION("ADIN1110 Network driver");
- MODULE_AUTHOR("Alexandru Tachici <[email protected]>");
- MODULE_LICENSE("Dual BSD/GPL");
|