shithub: riscv

Download patch

ref: 9ad75b63d6b975b3ae6a69bc3c0a4638b4b18fbc
parent: e3920d71c6273b8d0c773b411717a2d0137ee0ec
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Sep 5 04:42:59 EDT 2022

ethervgbe: enable auto-negotiation and ipv6 (thanks arne)

--- a/sys/src/9/pc/ethervgbe.c
+++ b/sys/src/9/pc/ethervgbe.c
@@ -90,11 +90,32 @@
 
 	MiiAddr		= 0x71,			/* MII address */
 	MiiData		= 0x72,			/* MII data */
+	PhySts0		= 0x6e,			/* Phy Status */
+		PhySts_TxF			= 0x01,
+		PhySts_RxF			= 0x02,
+		PhySts_Speed10		= 0x04,
+		PhySts_Speed1000	= 0x08,
+		PhySts_Fd			= 0x10,
+		PhySts_Link			= 0x40,
+		PhySts_RestSts		= 0x80,
 
 	/* 64 bits related registers. */
 	TxDescHi	= 0x18,
 	DataBufHi	= 0x1d,
 
+	/* CAM Registers */
+	Cam0 		= 0x10,
+	CamAddr		= 0x68,
+		CamAddr_Enable	= 0x80,
+	CamCtl		= 0x69,
+		CamCtl_PageSel	= 0xc0,
+		CamCtl_Write	= 0x04,
+		CamCtl_Read		= 0x08,
+	CamPageSel	= 0x69,			/* Alias of CamCtl for better readability */
+		CamPageSel_Mar		= 0x00,
+		CamPageSel_CamMask	= 0x40,
+		CamPageSel_CamData	= 0x80,
+
 	/* Rx engine registers. */
 	RxDescLo	= 0x38,			/* Rx descriptor base address (lo 32 bits) */
 	RxCsrS		= 0x32,			/* Rx descriptor queue control/status (Set) */
@@ -311,6 +332,9 @@
 	int	active;
 	uchar	ea[6];
 
+	uchar maddrs[32][Eaddrlen];
+	uint camidx;
+
 	RxDesc*	rx_ring;
 	Block*	rx_blocks[RxCount];
 
@@ -339,6 +363,33 @@
 #define ciow(c, r, b)	wiow(c, r, riob(c, r) & ~b)
 #define ciol(c, r, b)	wiol(c, r, riob(c, r) & ~b)
 
+
+static void
+vgbemiip(Ctlr* ctlr, int on)
+{
+	int i;
+
+	wiob(ctlr, MiiCmd, 0);
+	wiob(ctlr, MiiAddr, 0x80);
+
+	for(i = 0; i < 10000; i++){
+		if(riob(ctlr, MiiStatus) & MiiStatus_idle)
+			break;
+		microdelay(1);
+	}
+
+	if(on == 0)
+		return;
+
+	wiob(ctlr, MiiCmd, MiiCmd_auto);
+
+	for(i = 0; i < 10000; i++){
+                if(riob(ctlr, MiiStatus) & MiiStatus_idle)
+                        break;
+                microdelay(1);
+        }
+}
+
 static int
 vgbemiiw(Mii* mii, int phy, int addr, int data)
 {
@@ -350,6 +401,8 @@
 
 	ctlr = mii->ctlr;
 
+	vgbemiip(ctlr, 0);
+
 	wiob(ctlr, MiiAddr, addr);
 	wiow(ctlr, MiiData, (ushort) data);
 	wiob(ctlr, MiiCmd, MiiCmd_write);
@@ -363,6 +416,8 @@
 		return -1;
 	}
 
+	vgbemiip(ctlr, 1);
+
 	return 0;
 }
 
@@ -371,6 +426,7 @@
 {
 	Ctlr* ctlr;
 	int i;
+	u16int r;
 
 	if(phy != 1)
 		return -1;
@@ -377,6 +433,8 @@
 
 	ctlr = mii->ctlr;
 
+	vgbemiip(ctlr, 0);
+
 	wiob(ctlr, MiiAddr, addr);
 	wiob(ctlr, MiiCmd, MiiCmd_read);
 
@@ -389,7 +447,11 @@
 		return -1;
 	}
 
-	return riow(ctlr, MiiData);
+	r = riow(ctlr, MiiData);
+
+	vgbemiip(ctlr, 1);
+
+	return r;
 }
 
 static long
@@ -652,9 +714,11 @@
 	if(status & Isr_PhyIntr)
 		print("vgbe: irq: PHY interrupt\n");
 
-	if(status & Isr_LinkStatus)
+	if(status & Isr_LinkStatus){
+		edev->link = (riob(ctlr, PhySts0) & PhySts_Link) ? 1 : 0;
+		vgbemiip(ctlr, 1);
 		print("vgbe: irq: link status change\n");
-
+	}
 	if(status & Isr_RxNoDesc)
 		print("vgbe: irq: ran out of Rx descriptors\n");
 
@@ -778,9 +842,21 @@
 	for(i = 0; i < RxCount; i++)
 		vgbenewrx(ctlr, i);
 
+
+	/* Clear CAM Filter */
+	ciob(ctlr, CamCtl, CamCtl_PageSel);
+	siob(ctlr, CamPageSel, CamPageSel_CamMask);
+	wiob(ctlr, CamAddr, CamAddr_Enable);
+	for(i = 0; i < 8; i++)
+		wiob(ctlr, Cam0+i, 0);
+
+	wiob(ctlr, CamAddr, 0);
+	ciob(ctlr, CamCtl, CamCtl_PageSel);
+	siob(ctlr, CamPageSel, CamPageSel_Mar);
+
 	/* Init Rx MAC. */
 	wiob(ctlr, RxControl,
-		RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast);
+		RxControl_BroadCast|RxControl_UniCast);
 	wiob(ctlr, RxConfig, RxConfig_VlanOpt0);
 
 	/* Load Rx ring. */
@@ -825,7 +901,7 @@
 static void
 vgbereset(Ctlr* ctlr)
 {
-//	MiiPhy* phy;
+	MiiPhy* phy;
 	int timeo, i;
 
 //	print("vgbe: reset\n");
@@ -898,8 +974,10 @@
 		return;
 	}
 
-//	phy = ctlr->mii->curphy;
-//	print("vgbe: phy:oui %#x\n", phy->oui);
+	phy = ctlr->mii->curphy;
+	print("vgbe: phy:oui %#x\n", phy->oui);
+
+	vgbemiip(ctlr, 1);
 }
 
 static void
@@ -1092,13 +1170,63 @@
 static void
 vgbepromiscuous(void* arg, int on)
 {
-	USED(arg, on);
+	Ether* edev;
+	Ctlr* ctlr;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+	if(on)
+	   siob(ctlr, RxControl, RxControl_Promisc | RxControl_MultiCast);
+	else
+	   ciob(ctlr, RxControl, RxControl_Promisc | RxControl_MultiCast);
 }
 
 /* multicast already on, don't need to do anything */
 static void
-vgbemulticast(void*, uchar*, int)
+vgbemulticast(void* ether, uchar* ea, int add)
 {
+	Ether* edev;
+	Ctlr* ctlr;
+	int i;
+
+	edev = ether;
+	ctlr = edev->ctlr;
+
+	if(!add || ctlr->camidx == 32)
+		return;
+
+	for(i = 0; i < ctlr->camidx; i++){
+		if(memcmp(ea, ctlr->maddrs[i], Eaddrlen) == 0)
+			return;
+	}
+
+	memmove(ctlr->maddrs[i], ea, Eaddrlen);
+
+	ciob(ctlr, CamCtl, CamCtl_PageSel);
+ 	siob(ctlr, CamPageSel, CamPageSel_CamData);
+
+	wiob(ctlr, CamAddr, CamAddr_Enable | ctlr->camidx);
+
+	for(i = 0; i < Eaddrlen; i++)
+		wiob(ctlr, Cam0+i, ea[i]);
+
+	siob(ctlr, CamCtl, CamCtl_Write);
+
+	for(i = 0; i < 10000; i++){
+		microdelay(1);
+		if((riob(ctlr, CamCtl) & CamCtl_Write) == 0)
+			break; 	
+	}
+	
+	ciob(ctlr, CamCtl, CamCtl_PageSel);
+	siob(ctlr, CamPageSel, CamPageSel_CamMask);
+	siob(ctlr, Cam0+(ctlr->camidx/8), 1<<(ctlr->camidx&7));
+
+	ctlr->camidx++;
+  
+	wiob(ctlr, CamAddr, 0);
+	ciob(ctlr, CamCtl, CamCtl_PageSel);
+	siob(ctlr, CamPageSel, CamPageSel_Mar);
 }
 
 static int
@@ -1134,11 +1262,12 @@
 	edev->irq = ctlr->pdev->intl;
 	edev->tbdf = ctlr->pdev->tbdf;
 	edev->mbps = 1000;
+	edev->link = (riob(ctlr, PhySts0) & PhySts_Link) ? 1 : 0;
 	memmove(edev->ea, ctlr->ea, Eaddrlen);
 	edev->attach = vgbeattach;
 	edev->transmit = vgbetransmit;
 	edev->ifstat = vgbeifstat;
-//	edev->promiscuous = vgbepromiscuous;
+	edev->promiscuous = vgbepromiscuous;
 	edev->multicast = vgbemulticast;
 //	edev->shutdown = vgbeshutdown;
 	edev->ctl = vgbectl;