nic3com.c 4.84 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * This file is part of the flashrom project.
 *
 * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */

#include <stdlib.h>
#include <string.h>
23 24 25
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
26 27 28 29 30 31 32 33 34 35 36 37 38 39
#include <errno.h>
#include "flash.h"

#define BIOS_ROM_ADDR		0x04
#define BIOS_ROM_DATA		0x08
#define INT_STATUS		0x0e
#define SELECT_REG_WINDOW	0x800

#define PCI_IO_BASE_ADDRESS	0x10

#define PCI_VENDOR_ID_3COM	0x10b7

uint32_t io_base_addr;
struct pci_access *pacc;
40
struct pci_filter filter;
41

42 43 44 45
#if defined(__FreeBSD__) || defined(__DragonFly__)
int io_fd;
#endif

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#define OK 0
#define NT 1	/* Not tested */

static struct nic_status {
	uint16_t device_id;
	int status;
	const char *device_name;
} nics[] = {
	/* 3C90xB */
	{0x9055, NT, "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"},
	{0x9001, NT, "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" },
	{0x9004, NT, "3C90xB: PCI 10BASE-T (TPO)" },
	{0x9005, NT, "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" },
	{0x9006, NT, "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" },
	{0x900a, NT, "3C90xB: PCI 10BASE-FL" },
	{0x905a, NT, "3C90xB: PCI 10BASE-FX" },

	/* 3C905C */
	{0x9200, OK, "3C905C: EtherLink 10/100 PCI (TX)" },

	/* 3C980C */
	{0x9805, NT, "3C980C: EtherLink Server 10/100 PCI (TX)" },

	{},
};

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
uint32_t nic3com_validate(struct pci_dev *dev)
{
	int i = 0;
	uint32_t addr = -1;

	for (i = 0; nics[i].device_name != NULL; i++) {
		if (dev->device_id != nics[i].device_id)
			continue;

		addr = pci_read_long(dev, PCI_IO_BASE_ADDRESS) & ~0x03;

		printf("Found NIC \"3COM %s\" (%04x:%04x), addr = 0x%x\n",
		       nics[i].device_name, PCI_VENDOR_ID_3COM,
		       nics[i].device_id, addr);

		if (nics[i].status == NT) {
			printf("===\nThis NIC is UNTESTED. Please email a "
			       "report including the 'flashrom -p nic3com'\n"
			       "output to flashrom@coreboot.org if it works "
			       "for you. Thank you for your help!\n===\n");
		}

		return addr;
	}

	return addr;
}

100 101 102
int nic3com_init(void)
{
	struct pci_dev *dev;
103
	char *msg = NULL;
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

#if defined (__sun) && (defined(__i386) || defined(__amd64))
	if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
#elif defined(__FreeBSD__) || defined (__DragonFly__)
	if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
#else
	if (iopl(3) != 0) {
#endif
		fprintf(stderr, "ERROR: Could not get IO privileges (%s).\n"
			"You need to be root.\n", strerror(errno));
		exit(1);
	}

	pacc = pci_alloc();     /* Get the pci_access structure */
	pci_init(pacc);         /* Initialize the PCI library */
	pci_scan_bus(pacc);     /* We want to get the list of devices */

121 122 123 124 125 126
	if (nic_pcidev != NULL) {
		pci_filter_init(pacc, &filter);
		
		if ((msg = pci_filter_parse_slot(&filter, nic_pcidev))) {
			fprintf(stderr, "Error: %s\n", msg);
			exit(1);
127
		}
128
	}
129

130 131 132
	if (!filter.vendor && !filter.device) {
		pci_filter_init(pacc, &filter);
		filter.vendor = PCI_VENDOR_ID_3COM;
133 134
	}

135 136 137 138 139
	dev = pci_dev_find_filter(filter);

	if (dev && (dev->vendor_id == PCI_VENDOR_ID_3COM))
		io_base_addr = nic3com_validate(dev);
	else {
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
		fprintf(stderr, "Error: No supported 3COM NIC found.\n");
		exit(1);
	}

	/*
	 * The lowest 16 bytes of the I/O mapped register space of (most) 3COM
	 * cards form a 'register window' into one of multiple (usually 8)
	 * register banks. For 3C90xB/3C90xC we need register window/bank 0.
	 */
	OUTW(SELECT_REG_WINDOW + 0, io_base_addr + INT_STATUS);

	return 0;
}

int nic3com_shutdown(void)
{
156 157
	free(nic_pcidev);
	pci_cleanup(pacc);
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
	return 0;
}

void *nic3com_map(const char *descr, unsigned long phys_addr, size_t len)
{
	return 0;
}

void nic3com_unmap(void *virt_addr, size_t len)
{
}

void nic3com_chip_writeb(uint8_t val, volatile void *addr)
{
	OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
	OUTB(val, io_base_addr + BIOS_ROM_DATA);
}

void nic3com_chip_writew(uint16_t val, volatile void *addr)
{
}

void nic3com_chip_writel(uint32_t val, volatile void *addr)
{
}

uint8_t nic3com_chip_readb(const volatile void *addr)
{
	uint8_t val;

	OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
	val = INB(io_base_addr + BIOS_ROM_DATA);

	return val;
}

uint16_t nic3com_chip_readw(const volatile void *addr)
{
	return 0xffff;
}

uint32_t nic3com_chip_readl(const volatile void *addr)
{
	return 0xffffffff;
}