[PATCH 1/2] introduced some necessary read/write csr/bcr functions
--- src/pcnet.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 88 insertions(+), 0 deletions(-) diff --git a/src/pcnet.c b/src/pcnet.c index c2f9731..480a67f 100644 --- a/src/pcnet.c +++ b/src/pcnet.c @@ -33,6 +33,64 @@ enum { PCNET_IOSIZE_LEN = 0x20, }; +enum { + PCNET_IO_PROM = 0x0, + PCNET_IO_RDP = 0x10, + PCNET_IO_RAP = 0x12, + PCNET_IO_RESET = 0x14, + PCNET_IO_BDP = 0x16, +}; + +enum { + PCNET_IO32_PROM = 0x0, + PCNET_IO32_RDP = 0x10, + PCNET_IO32_RAP = 0x14, + PCNET_IO32_RESET = 0x18, + PCNET_IO32_BDP = 0x1c, +}; + +enum { + CSR0 = 0, + CSR1 = 1, + CSR2 = 2, + CSR4 = 4, + CSR15 = 15, + /* missed frame count */ + CSR112 = 112, +}; + +enum { + BCR18 = 18, +}; + +enum { + CSR0_INIT = 0x0001, + CSR0_START= 0x0002, + CSR0_STOP = 0x0004, + /* transmit demand */ + CSR0_TDMD = 0x0008, + /* transmitter on */ + CSR0_TXON = 0x0010, + /* receiver on */ + CSR0_RXON = 0x0020, + /* interrupt enable */ + CSR0_IENA = 0x0040, + CSR0_INTR = 0x0080, + /* initialisation done */ + CSR0_IDON = 0x0100, + CSR0_TINT = 0x0200, + CSR0_RINT = 0x0400, + CSR0_MERR = 0x0800, + CSR0_MISS = 0x1000, + CSR0_CERR = 0x2000, + CSR0_BABL = 0x4000, + CSR0_ERR = 0x8000, +}; + +enum { + BCR18_DWIO = 0x0080, +}; + /* PCnet-PCI II controller initialization includes the reading * of the initialization block in memory to obtain the operat- * ing parameters. @@ -94,6 +152,36 @@ struct pcnet_dummy_private { void __iomem *base; }; +static unsigned short pcnet_dummy_csr_read16(void __iomem *ioaddr, + unsigned short csr) +{ + iowrite16(csr, ioaddr + PCNET_IO_RAP); + return ioread16(ioaddr + PCNET_IO_RDP); +} + +static unsigned long pcnet_dummy_csr_read32(void __iomem *ioaddr, + unsigned long csr) +{ + iowrite32(csr, ioaddr + PCNET_IO32_RAP); + /* 16 most significant bits are undefined */ + return ioread32(ioaddr + PCNET_IO32_RDP) & 0xffff; +} + +static void pcnet_dummy_csr_write32(void __iomem *ioaddr, + unsigned long data, unsigned long csr) +{ + iowrite32(csr, ioaddr + PCNET_IO32_RAP); + iowrite32(data, ioaddr + PCNET_IO32_RDP); +} + +static unsigned long pcnet_dummy_bcr_read32(void __iomem *ioaddr, + unsigned long bcr) +{ + iowrite32(bcr, ioaddr + PCNET_IO32_RAP); + /* 16 most significant bits are undefined */ + return ioread32(ioaddr + PCNET_IO32_BDP) & 0xffff; +} + static int pcnet_dummy_open(struct net_device *ndev) { return 0; -- 1.7.5.rc3
Soft reset (S_RESET) resets value of CSR0 to default. The default value for CSR0 is 0x0004 (STOP bit is set) [2 p.23]. At first, assume we in word i/o mode and try to read 0x14. After this try to read 0x18 if CSR0 hasn't been set to default value. After S_RESET the controller will be in word i/o mode [1 p.101]. We need to perform 32bit write access to the i/o location at 0x10 to switch the controller to dword i/o mode [1 p.104]. Zero is safe value for this operation [1 p.104]. DWIO bit of BCR18 indicates that the controller is working in dword mode, if it isn't set something wrong occurred. [1] Am79C970A [2] PCnet Family Software Design Considerations --- src/pcnet.c | 19 ++++++++++++++++++- 1 files changed, 18 insertions(+), 1 deletions(-) diff --git a/src/pcnet.c b/src/pcnet.c index 480a67f..2372ec3 100644 --- a/src/pcnet.c +++ b/src/pcnet.c @@ -182,6 +182,21 @@ static unsigned long pcnet_dummy_bcr_read32(void __iomem *ioaddr, return ioread32(ioaddr + PCNET_IO32_BDP) & 0xffff; } +/* resets the controller and switches to 32bit mode */ +static int pcnet_dummy_reset(void __iomem *ioaddr) +{ + int err = 0; + ioread16(ioaddr + PCNET_IO_RESET); + if (pcnet_dummy_csr_read16(ioaddr, CSR0) != CSR0_STOP) + ioread32(ioaddr + PCNET_IO32_RESET); + iowrite32(0, ioaddr + PCNET_IO_RDP); + if (!(pcnet_dummy_bcr_read32(ioaddr, BCR18) & BCR18_DWIO)) { + printk(KERN_ERR DRV_NAME ": cannot switch controller to 32bit mode\n"); + err = -ENODEV; + } + return err; +} + static int pcnet_dummy_open(struct net_device *ndev) { return 0; @@ -236,7 +251,6 @@ static int __devinit pcnet_dummy_init_netdev(struct pci_dev *pdev, #endif /* HAVE_NET_DEVICE_OPS */ /* registers net_device and returns err */ - /* TODO: reset the chip at the end */ return 0; } @@ -272,6 +286,9 @@ static int __devinit pcnet_dummy_init_one(struct pci_dev *pdev, goto out_res; pci_set_drvdata(pdev, ndev); + if (pcnet_dummy_reset(ioaddr)) + goto out_res_unmap; + if (pcnet_dummy_init_netdev(pdev, (unsigned long)ioaddr)) goto out_res_unmap; -- 1.7.5.rc3
Soft reset (S_RESET) resets value of CSR0 to default. The default value for CSR0 is 0x0004 (STOP bit is set) [2 p.23]. At first, assume we in word i/o mode and try to read 0x14. After this try to read 0x18 if CSR0 hasn't been set to default value. After S_RESET the controller will be in word i/o mode [1 p.101]. We need to perform 32bit write access to the i/o location at 0x10 to switch the controller to dword i/o mode [1 p.104]. Zero is safe value for this operation [1 p.104]. DWIO bit of BCR18 indicates that the controller is working in dword mode, if it isn't set something wrong occurred.
[1] Am79C970A [2] PCnet Family Software Design Considerations --- src/pcnet.c | 19 ++++++++++++++++++- 1 files changed, 18 insertions(+), 1 deletions(-)
diff --git a/src/pcnet.c b/src/pcnet.c index 480a67f..2372ec3 100644 --- a/src/pcnet.c +++ b/src/pcnet.c @@ -182,6 +182,21 @@ static unsigned long pcnet_dummy_bcr_read32(void __iomem *ioaddr, return ioread32(ioaddr + PCNET_IO32_BDP) & 0xffff; }
+/* resets the controller and switches to 32bit mode */ +static int pcnet_dummy_reset(void __iomem *ioaddr) +{ + int err = 0; + ioread16(ioaddr + PCNET_IO_RESET); + if (pcnet_dummy_csr_read16(ioaddr, CSR0) != CSR0_STOP) + ioread32(ioaddr + PCNET_IO32_RESET); + iowrite32(0, ioaddr + PCNET_IO_RDP); + if (!(pcnet_dummy_bcr_read32(ioaddr, BCR18) & BCR18_DWIO)) { + printk(KERN_ERR DRV_NAME ": cannot switch controller to 32bit mode\n"); + err = -ENODEV; + } + return err; +} + static int pcnet_dummy_open(struct net_device *ndev) { return 0; @@ -236,7 +251,6 @@ static int __devinit pcnet_dummy_init_netdev(struct pci_dev *pdev, #endif /* HAVE_NET_DEVICE_OPS */ /* registers net_device and returns err */ - /* TODO: reset the chip at the end */
return 0; } @@ -272,6 +286,9 @@ static int __devinit pcnet_dummy_init_one(struct pci_dev *pdev, goto out_res; pci_set_drvdata(pdev, ndev);
+ if (pcnet_dummy_reset(ioaddr)) + goto out_res_unmap; + if (pcnet_dummy_init_netdev(pdev, (unsigned long)ioaddr)) goto out_res_unmap;
Приветствую после длительного перерыва. Заметил следующую особенность: если перед выгрузкой модуля не переключить контроллер в 16бит режим, то оригинальный драйвер pcnet32, загруженный после pcnet-dummy, не обнаружит сетевую карту. Но он сбросит контроллер в 16бит режим, после чего при повторной его загрузке карточка обнаружится. Поэтому выдвигаю предложение разбить функцию pcnet_dummy_reset() на две: reset и switch_to_32, и вызывать reset в remove_one() Есть ли замечания? -- Best regards, Dmitry Podgorny
participants (1)
-
Dmitry Podgorny