mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [RFC v4 0/6] barebox PCI support
@ 2014-06-30 19:59 Antony Pavlov
  2014-06-30 19:59 ` [RFC v4 1/6] MIPS: add dma_alloc_coherent() Antony Pavlov
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Antony Pavlov @ 2014-06-30 19:59 UTC (permalink / raw)
  To: barebox

This patchseries introduce simple PCI bus support for barebox.

Changes since RFC v3:

  * rebase over latest 'next';
  * use list for pci_root_buses;
  * move common PCI Kconfig stuff from arch/mips to drivers/pci;
  * make pci_*_write_config_* PCIe-friendly (use 'int' type for
    config register address);
  * drop some unused stuff;
  * change lspci "no pci" error message to "No PCI bus detected";
  * rtl8139: use dma_alloc_coherent();
  * rtl8139: use pci_set_master() & pci_clear_master().

TODOs for RFC v3:

  * no PCI bridges support;
  * introduce pci_resource_start();
  * introduce pci_iomap();
  * clean '#if 0'.

This patchseries can be found on github:

  https://github.com/frantony/barebox/tree/pci.20140630

Antony Pavlov (6):
  MIPS: add dma_alloc_coherent()
  PCI: initial commit
  commands: add 'lspci' command
  net: add RealTek RTL-8139 PCI Ethernet driver
  MIPS: add PCI support for GT64120-based Malta board
  MIPS: qemu-malta_defconfig: enable PCI & network stuff

 arch/mips/Kconfig                                |   1 +
 arch/mips/configs/qemu-malta_defconfig           |   4 +
 arch/mips/include/asm/dma-mapping.h              |  25 +
 arch/mips/include/asm/gt64120.h                  |  53 ++
 arch/mips/mach-malta/Makefile                    |   1 +
 arch/mips/mach-malta/include/mach/mach-gt64120.h |   2 +
 arch/mips/mach-malta/pci.c                       | 236 +++++++++
 commands/Kconfig                                 |   8 +
 commands/Makefile                                |   1 +
 commands/lspci.c                                 |  52 ++
 drivers/Kconfig                                  |   1 +
 drivers/Makefile                                 |   1 +
 drivers/net/Kconfig                              |   8 +
 drivers/net/Makefile                             |   1 +
 drivers/net/rtl8139.c                            | 616 +++++++++++++++++++++++
 drivers/pci/Kconfig                              |  29 ++
 drivers/pci/Makefile                             |   8 +
 drivers/pci/bus.c                                | 110 ++++
 drivers/pci/pci.c                                | 285 +++++++++++
 include/linux/mod_devicetable.h                  |  20 +
 include/linux/pci.h                              | 292 +++++++++++
 include/linux/pci_ids.h                          | 141 ++++++
 include/linux/pci_regs.h                         | 110 ++++
 23 files changed, 2005 insertions(+)
 create mode 100644 arch/mips/include/asm/dma-mapping.h
 create mode 100644 arch/mips/mach-malta/pci.c
 create mode 100644 commands/lspci.c
 create mode 100644 drivers/net/rtl8139.c
 create mode 100644 drivers/pci/Kconfig
 create mode 100644 drivers/pci/Makefile
 create mode 100644 drivers/pci/bus.c
 create mode 100644 drivers/pci/pci.c
 create mode 100644 include/linux/mod_devicetable.h
 create mode 100644 include/linux/pci.h
 create mode 100644 include/linux/pci_ids.h
 create mode 100644 include/linux/pci_regs.h

-- 
1.9.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v4 1/6] MIPS: add dma_alloc_coherent()
  2014-06-30 19:59 [RFC v4 0/6] barebox PCI support Antony Pavlov
@ 2014-06-30 19:59 ` Antony Pavlov
  2014-06-30 19:59 ` [RFC v4 2/6] PCI: initial commit Antony Pavlov
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Antony Pavlov @ 2014-06-30 19:59 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 arch/mips/include/asm/dma-mapping.h | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h
new file mode 100644
index 0000000..555efa5
--- /dev/null
+++ b/arch/mips/include/asm/dma-mapping.h
@@ -0,0 +1,25 @@
+#ifndef _ASM_DMA_MAPPING_H
+#define _ASM_DMA_MAPPING_H
+
+#include <xfuncs.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <malloc.h>
+
+static inline void *dma_alloc_coherent(size_t size, dma_addr_t *dma_handle)
+{
+	void *ret;
+
+	ret = xmemalign(PAGE_SIZE, size);
+
+	*dma_handle = CPHYSADDR(ret);
+
+	return (void *)CKSEG1ADDR(ret);
+}
+
+static inline void dma_free_coherent(void *vaddr)
+{
+	free(vaddr);
+}
+
+#endif /* _ASM_DMA_MAPPING_H */
-- 
1.9.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v4 2/6] PCI: initial commit
  2014-06-30 19:59 [RFC v4 0/6] barebox PCI support Antony Pavlov
  2014-06-30 19:59 ` [RFC v4 1/6] MIPS: add dma_alloc_coherent() Antony Pavlov
@ 2014-06-30 19:59 ` Antony Pavlov
  2014-07-02  6:12   ` Sascha Hauer
  2014-06-30 19:59 ` [RFC v4 3/6] commands: add 'lspci' command Antony Pavlov
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Antony Pavlov @ 2014-06-30 19:59 UTC (permalink / raw)
  To: barebox

used shorten version of linux-2.6.39 pci_ids.h

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 drivers/Kconfig                 |   1 +
 drivers/Makefile                |   1 +
 drivers/pci/Kconfig             |  29 ++++
 drivers/pci/Makefile            |   8 ++
 drivers/pci/bus.c               | 110 +++++++++++++++
 drivers/pci/pci.c               | 285 +++++++++++++++++++++++++++++++++++++++
 include/linux/mod_devicetable.h |  20 +++
 include/linux/pci.h             | 292 ++++++++++++++++++++++++++++++++++++++++
 include/linux/pci_ids.h         | 136 +++++++++++++++++++
 include/linux/pci_regs.h        | 110 +++++++++++++++
 10 files changed, 992 insertions(+)

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 53e1e97..12a9d8c 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -27,5 +27,6 @@ source "drivers/pinctrl/Kconfig"
 source "drivers/bus/Kconfig"
 source "drivers/regulator/Kconfig"
 source "drivers/reset/Kconfig"
+source "drivers/pci/Kconfig"
 
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index ef3604f..1990e86 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -26,3 +26,4 @@ obj-y += pinctrl/
 obj-y += bus/
 obj-$(CONFIG_REGULATOR) += regulator/
 obj-$(CONFIG_RESET_CONTROLLER) += reset/
+obj-$(CONFIG_PCI) += pci/
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
new file mode 100644
index 0000000..9e46592
--- /dev/null
+++ b/drivers/pci/Kconfig
@@ -0,0 +1,29 @@
+config HW_HAS_PCI
+	bool
+
+if HW_HAS_PCI
+
+menu "PCI bus options"
+
+config PCI
+	bool "Support for PCI controller"
+	depends on HW_HAS_PCI
+	help
+	  Find out whether you have a PCI motherboard. PCI is the name of a
+	  bus system, i.e. the way the CPU talks to the other stuff inside
+	  your box. If you have PCI, say Y, otherwise N.
+
+
+config PCI_DEBUG
+	bool "PCI Debugging"
+	depends on PCI
+	help
+	  Say Y here if you want the PCI core to produce a bunch of debug
+	  messages to the system log.  Select this if you are having a
+	  problem with PCI support and want to see more of what is going on.
+
+	  When in doubt, say N.
+
+endmenu
+
+endif
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
new file mode 100644
index 0000000..c7d43c3
--- /dev/null
+++ b/drivers/pci/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the PCI bus specific drivers.
+#
+obj-y		+= pci.o bus.o
+
+ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
+
+CPPFLAGS += $(ccflags-y)
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
new file mode 100644
index 0000000..8215ee5
--- /dev/null
+++ b/drivers/pci/bus.c
@@ -0,0 +1,110 @@
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <linux/pci.h>
+
+/**
+ * pci_match_one_device - Tell if a PCI device structure has a matching
+ *                        PCI device id structure
+ * @id: single PCI device id structure to match
+ * @dev: the PCI device structure to match against
+ *
+ * Returns the matching pci_device_id structure or %NULL if there is no match.
+ */
+static inline const struct pci_device_id *
+pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
+{
+	if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
+	    (id->device == PCI_ANY_ID || id->device == dev->device) &&
+	    (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&
+	    (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&
+	    !((id->class ^ dev->class) & id->class_mask))
+		return id;
+	return NULL;
+}
+
+static int pci_match(struct device_d *dev, struct driver_d *drv)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pci_driver *pdrv = to_pci_driver(drv);
+	struct pci_device_id *id;
+
+	for (id = (struct pci_device_id *)pdrv->id_table; id->vendor; id++)
+		if (pci_match_one_device(id, pdev)) {
+			dev->priv = id;
+			return 0;
+		}
+
+	return -1;
+}
+
+static int pci_probe(struct device_d *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pci_driver *pdrv = to_pci_driver(dev->driver);
+
+	return pdrv->probe(pdev, dev->priv);
+}
+
+static void pci_remove(struct device_d *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pci_driver *pdrv = to_pci_driver(dev->driver);
+
+	pdrv->remove(pdev);
+}
+
+struct bus_type pci_bus = {
+	.name = "pci",
+	.match = pci_match,
+	.probe = pci_probe,
+	.remove = pci_remove,
+};
+
+static int pci_bus_init(void)
+{
+	return bus_register(&pci_bus);
+}
+pure_initcall(pci_bus_init);
+
+int pci_register_driver(struct pci_driver *pdrv)
+{
+	struct driver_d *drv = &pdrv->driver;
+
+	if (!pdrv->id_table)
+		return -EIO;
+
+	drv->name = pdrv->name;
+	drv->bus = &pci_bus;
+
+	return register_driver(drv);
+}
+
+int pci_register_device(struct pci_dev *pdev)
+{
+	char str[6];
+	struct device_d *dev = &pdev->dev;
+	int ret;
+
+	strcpy(dev->name, "pci");
+	dev->bus = &pci_bus;
+	dev->id = DEVICE_ID_DYNAMIC;
+
+	ret = register_device(dev);
+
+	if (ret)
+		return ret;
+
+	sprintf(str, "%02x", pdev->devfn);
+	dev_add_param_fixed(dev, "devfn", str);
+	sprintf(str, "%04x", (pdev->class >> 8) & 0xffff);
+	dev_add_param_fixed(dev, "class", str);
+	sprintf(str, "%04x", pdev->vendor);
+	dev_add_param_fixed(dev, "vendor", str);
+	sprintf(str, "%04x", pdev->device);
+	dev_add_param_fixed(dev, "device", str);
+	sprintf(str, "%04x", pdev->revision);
+	dev_add_param_fixed(dev, "revision", str);
+
+	return 0;
+}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
new file mode 100644
index 0000000..554cf64
--- /dev/null
+++ b/drivers/pci/pci.c
@@ -0,0 +1,285 @@
+#include <common.h>
+#include <linux/pci.h>
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+static struct pci_controller *hose_head, **hose_tail = &hose_head;
+
+LIST_HEAD(pci_root_buses);
+EXPORT_SYMBOL(pci_root_buses);
+
+static struct pci_bus *pci_alloc_bus(void)
+{
+	struct pci_bus *b;
+
+	b = kzalloc(sizeof(*b), GFP_KERNEL);
+	if (b) {
+		INIT_LIST_HEAD(&b->node);
+		INIT_LIST_HEAD(&b->children);
+		INIT_LIST_HEAD(&b->devices);
+		INIT_LIST_HEAD(&b->slots);
+		INIT_LIST_HEAD(&b->resources);
+	}
+	return b;
+}
+
+void register_pci_controller(struct pci_controller *hose)
+{
+	struct pci_bus *bus;
+
+	*hose_tail = hose;
+	hose_tail = &hose->next;
+
+	bus = pci_alloc_bus();
+	hose->bus = bus;
+	bus->ops = hose->pci_ops;
+	bus->resource[0] = hose->mem_resource;
+	bus->resource[1] = hose->io_resource;
+
+	pci_scan_bus(bus);
+
+	list_add_tail(&bus->node, &pci_root_buses);
+
+	return;
+}
+
+/*
+ *  Wrappers for all PCI configuration access functions.  They just check
+ *  alignment, do locking and call the low-level functions pointed to
+ *  by pci_dev->ops.
+ */
+
+#define PCI_byte_BAD 0
+#define PCI_word_BAD (pos & 1)
+#define PCI_dword_BAD (pos & 3)
+
+#define PCI_OP_READ(size,type,len) \
+int pci_bus_read_config_##size \
+	(struct pci_bus *bus, unsigned int devfn, int pos, type *value)	\
+{									\
+	int res;							\
+	u32 data = 0;							\
+	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
+	res = bus->ops->read(bus, devfn, pos, len, &data);		\
+	*value = (type)data;						\
+	return res;							\
+}
+
+#define PCI_OP_WRITE(size,type,len) \
+int pci_bus_write_config_##size \
+	(struct pci_bus *bus, unsigned int devfn, int pos, type value)	\
+{									\
+	int res;							\
+	if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;	\
+	res = bus->ops->write(bus, devfn, pos, len, value);		\
+	return res;							\
+}
+
+PCI_OP_READ(byte, u8, 1)
+PCI_OP_READ(word, u16, 2)
+PCI_OP_READ(dword, u32, 4)
+PCI_OP_WRITE(byte, u8, 1)
+PCI_OP_WRITE(word, u16, 2)
+PCI_OP_WRITE(dword, u32, 4)
+
+EXPORT_SYMBOL(pci_bus_read_config_byte);
+EXPORT_SYMBOL(pci_bus_read_config_word);
+EXPORT_SYMBOL(pci_bus_read_config_dword);
+EXPORT_SYMBOL(pci_bus_write_config_byte);
+EXPORT_SYMBOL(pci_bus_write_config_word);
+EXPORT_SYMBOL(pci_bus_write_config_dword);
+
+static struct pci_dev *alloc_pci_dev(void)
+{
+	struct pci_dev *dev;
+
+	dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	INIT_LIST_HEAD(&dev->bus_list);
+
+	return dev;
+}
+
+unsigned int pci_scan_bus(struct pci_bus *bus)
+{
+	unsigned int devfn, l, max, class;
+	unsigned char cmd, tmp, hdr_type, is_multi = 0;
+	struct pci_dev *dev;
+	resource_size_t last_mem;
+	resource_size_t last_io;
+
+	/* FIXME: use res_start() */
+	last_mem = bus->resource[0]->start;
+	last_io = bus->resource[1]->start;
+
+	DBG("pci_scan_bus for bus %d\n", bus->number);
+	DBG(" last_io = 0x%08x, last_mem = 0x%08x\n", last_io, last_mem);
+	max = bus->secondary;
+
+	for (devfn = 0; devfn < 0xff; ++devfn) {
+		int bar;
+		u32 old_bar, mask;
+		int size;
+
+		if (PCI_FUNC(devfn) && !is_multi) {
+			/* not a multi-function device */
+			continue;
+		}
+		if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type))
+			continue;
+		if (!PCI_FUNC(devfn))
+			is_multi = hdr_type & 0x80;
+
+		if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l) ||
+		    /* some broken boards return 0 if a slot is empty: */
+		    l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
+			continue;
+
+		dev = alloc_pci_dev();
+		if (!dev)
+			return 0;
+
+		dev->bus = bus;
+		dev->devfn = devfn;
+		dev->vendor = l & 0xffff;
+		dev->device = (l >> 16) & 0xffff;
+
+		/* non-destructively determine if device can be a master: */
+		pci_read_config_byte(dev, PCI_COMMAND, &cmd);
+		pci_write_config_byte(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
+		pci_read_config_byte(dev, PCI_COMMAND, &tmp);
+		pci_write_config_byte(dev, PCI_COMMAND, cmd);
+
+		pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+		dev->revision = class & 0xff;
+		class >>= 8;				    /* upper 3 bytes */
+		dev->class = class;
+		class >>= 8;
+		dev->hdr_type = hdr_type;
+
+		DBG("PCI: class = %08x, hdr_type = %08x\n", class, hdr_type);
+
+		switch (hdr_type & 0x7f) {		    /* header type */
+		case PCI_HEADER_TYPE_NORMAL:		    /* standard header */
+			if (class == PCI_CLASS_BRIDGE_PCI)
+				goto bad;
+
+			/*
+			 * read base address registers, again pcibios_fixup() can
+			 * tweak these
+			 */
+			pci_read_config_dword(dev, PCI_ROM_ADDRESS, &l);
+			dev->rom_address = (l == 0xffffffff) ? 0 : l;
+			break;
+		default:				    /* unknown header */
+		bad:
+			printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
+			       bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);
+			continue;
+		}
+
+		DBG("PCI: %02x:%02x [%04x/%04x]\n", bus->number, dev->devfn, dev->vendor, dev->device);
+
+		list_add_tail(&dev->bus_list, &bus->devices);
+		pci_register_device(dev);
+
+		if (class == PCI_CLASS_BRIDGE_HOST) {
+			DBG("PCI: skip pci host bridge\n");
+			continue;
+		}
+
+		for (bar = 0; bar < 6; bar++) {
+			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &old_bar);
+			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, 0xfffffffe);
+			pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, &mask);
+			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, old_bar);
+
+			if (mask == 0 || mask == 0xffffffff) {
+				DBG("  PCI: pbar%d set bad mask\n", bar);
+				continue;
+			}
+
+			if (mask & 0x01) { /* IO */
+				size = -(mask & 0xfffffffe);
+				DBG("  PCI: pbar%d: mask=%08x io %d bytes\n", bar, mask, size);
+				pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_io);
+				last_io += size;
+
+			} else { /* MEM */
+				size = -(mask & 0xfffffff0);
+				DBG("  PCI: pbar%d: mask=%08x memory %d bytes\n", bar, mask, size);
+				pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + bar * 4, last_mem);
+				last_mem += size;
+			}
+		}
+	}
+
+	/*
+	 * We've scanned the bus and so we know all about what's on
+	 * the other side of any bridges that may be on this bus plus
+	 * any devices.
+	 *
+	 * Return how far we've got finding sub-buses.
+	 */
+	DBG("PCI: pci_scan_bus returning with max=%02x\n", max);
+
+	return max;
+}
+
+static void __pci_set_master(struct pci_dev *dev, bool enable)
+{
+	u16 old_cmd, cmd;
+
+	pci_read_config_word(dev, PCI_COMMAND, &old_cmd);
+	if (enable)
+		cmd = old_cmd | PCI_COMMAND_MASTER;
+	else
+		cmd = old_cmd & ~PCI_COMMAND_MASTER;
+	if (cmd != old_cmd) {
+		dev_dbg(&dev->dev, "%s bus mastering\n",
+			enable ? "enabling" : "disabling");
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+	}
+}
+
+/**
+ * pci_set_master - enables bus-mastering for device dev
+ * @dev: the PCI device to enable
+ */
+void pci_set_master(struct pci_dev *dev)
+{
+	__pci_set_master(dev, true);
+}
+EXPORT_SYMBOL(pci_set_master);
+
+/**
+ * pci_clear_master - disables bus-mastering for device dev
+ * @dev: the PCI device to disable
+ */
+void pci_clear_master(struct pci_dev *dev)
+{
+	__pci_set_master(dev, false);
+}
+EXPORT_SYMBOL(pci_clear_master);
+
+/**
+ * pci_enable_device - Initialize device before it's used by a driver.
+ * @dev: PCI device to be initialized
+ */
+int pci_enable_device(struct pci_dev *dev)
+{
+	u32 t;
+
+	pci_read_config_dword(dev, PCI_COMMAND, &t);
+	return pci_write_config_dword(dev, PCI_COMMAND, t
+				| PCI_COMMAND_IO
+				| PCI_COMMAND_MEMORY
+				);
+}
+EXPORT_SYMBOL(pci_enable_device);
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
new file mode 100644
index 0000000..c822075
--- /dev/null
+++ b/include/linux/mod_devicetable.h
@@ -0,0 +1,20 @@
+/*
+ * Device tables which are exported to userspace via
+ * scripts/mod/file2alias.c.  You must keep that file in sync with this
+ * header.
+ */
+
+#ifndef LINUX_MOD_DEVICETABLE_H
+#define LINUX_MOD_DEVICETABLE_H
+
+#include <linux/types.h>
+
+#define PCI_ANY_ID (~0)
+
+struct pci_device_id {
+	__u32 vendor, device;		/* Vendor and device ID or PCI_ANY_ID*/
+	__u32 subvendor, subdevice;	/* Subsystem ID's or PCI_ANY_ID */
+	__u32 class, class_mask;	/* (class,subclass,prog-if) triplet */
+};
+
+#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
new file mode 100644
index 0000000..759aea6
--- /dev/null
+++ b/include/linux/pci.h
@@ -0,0 +1,292 @@
+/*
+ *	pci.h
+ *
+ *	PCI defines and function prototypes
+ *	Copyright 1994, Drew Eckhardt
+ *	Copyright 1997--1999 Martin Mares <mj@ucw.cz>
+ *
+ *	For more information, please consult the following manuals (look at
+ *	http://www.pcisig.com/ for how to get them):
+ *
+ *	PCI BIOS Specification
+ *	PCI Local Bus Specification
+ *	PCI to PCI Bridge Specification
+ *	PCI System Design Guide
+ */
+#ifndef LINUX_PCI_H
+#define LINUX_PCI_H
+
+#include <linux/mod_devicetable.h>
+
+#include <linux/pci_regs.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include <errno.h>
+#include <io.h>
+
+#include <linux/pci_ids.h>
+
+
+/*
+ * The PCI interface treats multi-function devices as independent
+ * devices.  The slot/function address of each device is encoded
+ * in a single byte as follows:
+ *
+ *	7:3 = slot
+ *	2:0 = function
+ */
+#define PCI_DEVFN(slot, func)	((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define PCI_SLOT(devfn)		(((devfn) >> 3) & 0x1f)
+#define PCI_FUNC(devfn)		((devfn) & 0x07)
+
+/*
+ *  For PCI devices, the region numbers are assigned this way:
+ */
+enum {
+	/* #0-5: standard PCI resources */
+	PCI_STD_RESOURCES,
+	PCI_STD_RESOURCE_END = 5,
+
+	/* #6: expansion ROM resource */
+	PCI_ROM_RESOURCE,
+
+	/* device specific resources */
+#ifdef CONFIG_PCI_IOV
+	PCI_IOV_RESOURCES,
+	PCI_IOV_RESOURCE_END = PCI_IOV_RESOURCES + PCI_SRIOV_NUM_BARS - 1,
+#endif
+
+	/* resources assigned to buses behind the bridge */
+#define PCI_BRIDGE_RESOURCE_NUM 4
+
+	PCI_BRIDGE_RESOURCES,
+	PCI_BRIDGE_RESOURCE_END = PCI_BRIDGE_RESOURCES +
+				  PCI_BRIDGE_RESOURCE_NUM - 1,
+
+	/* total resources associated with a PCI device */
+	PCI_NUM_RESOURCES,
+
+	/* preserve this for compatibility */
+	DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES,
+};
+
+/*
+ * Error values that may be returned by PCI functions.
+ */
+#define PCIBIOS_SUCCESSFUL		0x00
+#define PCIBIOS_FUNC_NOT_SUPPORTED	0x81
+#define PCIBIOS_BAD_VENDOR_ID		0x83
+#define PCIBIOS_DEVICE_NOT_FOUND	0x86
+#define PCIBIOS_BAD_REGISTER_NUMBER	0x87
+#define PCIBIOS_SET_FAILED		0x88
+#define PCIBIOS_BUFFER_TOO_SMALL	0x89
+
+/*
+ * The pci_dev structure is used to describe PCI devices.
+ */
+struct pci_dev {
+	struct list_head bus_list;	/* node in per-bus list */
+	struct pci_bus	*bus;		/* bus this device is on */
+	struct pci_bus	*subordinate;	/* bus this device bridges to */
+
+	void		*sysdata;	/* hook for sys-specific extension */
+	struct proc_dir_entry *procent;	/* device entry in /proc/bus/pci */
+	struct pci_slot	*slot;		/* Physical slot this device is in */
+
+	struct device_d dev;
+
+	unsigned int	devfn;		/* encoded device & function index */
+	unsigned short	vendor;
+	unsigned short	device;
+	unsigned short	subsystem_vendor;
+	unsigned short	subsystem_device;
+	unsigned int	class;		/* 3 bytes: (base,sub,prog-if) */
+	u8		revision;	/* PCI revision, low byte of class word */
+	u8		hdr_type;	/* PCI header type (`multi' flag masked out) */
+
+	struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
+
+	/* Base registers for this device, can be adjusted by
+	 * pcibios_fixup() as necessary.
+	 */
+	unsigned long	base_address[6];
+	unsigned long	rom_address;
+};
+#define	to_pci_dev(dev) container_of(dev, struct pci_dev, dev)
+
+struct pci_bus {
+	struct list_head node;		/* node in list of buses */
+	struct pci_bus	*parent;	/* parent bus this bridge is on */
+	struct list_head children;	/* list of child buses */
+	struct list_head devices;	/* list of devices on this bus */
+	struct pci_dev	*self;		/* bridge device as seen by parent */
+	struct list_head slots;		/* list of slots on this bus */
+	struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];
+	struct list_head resources;	/* address space routed to this bus */
+
+	struct pci_ops	*ops;		/* configuration access functions */
+	void		*sysdata;	/* hook for sys-specific extension */
+	struct proc_dir_entry *procdir;	/* directory entry in /proc/bus/pci */
+
+	unsigned char	number;		/* bus number */
+	unsigned char	primary;	/* number of primary bridge */
+	unsigned char	secondary;	/* number of secondary bridge */
+	unsigned char	subordinate;	/* max number of subordinate buses */
+
+	char		name[48];
+};
+
+/* Low-level architecture-dependent routines */
+
+struct pci_ops {
+	int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val);
+	int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val);
+
+	/* return memory address for pci resource */
+	int (*res_start)(struct pci_bus *bus, resource_size_t res_addr);
+};
+
+extern struct pci_ops *pci_ops;
+
+/*
+ * Each pci channel is a top-level PCI bus seem by CPU.  A machine  with
+ * multiple PCI channels may have multiple PCI host controllers or a
+ * single controller supporting multiple channels.
+ */
+struct pci_controller {
+	struct pci_controller *next;
+	struct pci_bus *bus;
+
+	struct pci_ops *pci_ops;
+	struct resource *mem_resource;
+	unsigned long mem_offset;
+	struct resource *io_resource;
+	unsigned long io_offset;
+	unsigned long io_map_base;
+
+	unsigned int index;
+
+	/* Optional access methods for reading/writing the bus number
+	   of the PCI controller */
+	int (*get_busno)(void);
+	void (*set_busno)(int busno);
+};
+
+struct pci_driver {
+	struct list_head node;
+	const char *name;
+	const struct pci_device_id *id_table;	/* must be non-NULL for probe to be called */
+	int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id);	/* New device inserted */
+	void (*remove) (struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
+	struct driver_d	driver;
+};
+
+#define	to_pci_driver(drv) container_of(drv, struct pci_driver, driver)
+
+/**
+ * DEFINE_PCI_DEVICE_TABLE - macro used to describe a pci device table
+ * @_table: device table name
+ *
+ * This macro is used to create a struct pci_device_id array (a device table)
+ * in a generic manner.
+ */
+#define DEFINE_PCI_DEVICE_TABLE(_table) \
+	const struct pci_device_id _table[]
+
+/**
+ * PCI_DEVICE - macro used to describe a specific pci device
+ * @vend: the 16 bit PCI Vendor ID
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific device.  The subvendor and subdevice fields will be set to
+ * PCI_ANY_ID.
+ */
+#define PCI_DEVICE(vend, dev) \
+	.vendor = (vend), .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+/**
+ * PCI_DEVICE_CLASS - macro used to describe a specific pci device class
+ * @dev_class: the class, subclass, prog-if triple for this device
+ * @dev_class_mask: the class mask for this device
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI class.  The vendor, device, subvendor, and subdevice
+ * fields will be set to PCI_ANY_ID.
+ */
+#define PCI_DEVICE_CLASS(dev_class, dev_class_mask) \
+	.class = (dev_class), .class_mask = (dev_class_mask), \
+	.vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID
+
+/**
+ * PCI_VDEVICE - macro used to describe a specific pci device in short form
+ * @vend: the vendor name
+ * @dev: the 16 bit PCI Device ID
+ *
+ * This macro is used to create a struct pci_device_id that matches a
+ * specific PCI device.  The subvendor, and subdevice fields will be set
+ * to PCI_ANY_ID. The macro allows the next field to follow as the device
+ * private data.
+ */
+
+#define PCI_VDEVICE(vend, dev) \
+	.vendor = PCI_VENDOR_ID_##vend, .device = (dev), \
+	.subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0
+
+int pci_register_driver(struct pci_driver *pdrv);
+int pci_register_device(struct pci_dev *pdev);
+
+extern struct list_head pci_root_buses; /* list of all known PCI buses */
+
+extern unsigned int pci_scan_bus(struct pci_bus *bus);
+extern void register_pci_controller(struct pci_controller *hose);
+
+int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn,
+			     int where, u8 *val);
+int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn,
+			     int where, u16 *val);
+int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn,
+			      int where, u32 *val);
+int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn,
+			      int where, u8 val);
+int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn,
+			      int where, u16 val);
+int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn,
+			       int where, u32 val);
+
+static inline int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val)
+{
+	return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
+}
+static inline int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
+{
+	return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
+}
+static inline int pci_read_config_dword(const struct pci_dev *dev, int where,
+					u32 *val)
+{
+	return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val);
+}
+static inline int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val)
+{
+	return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val);
+}
+static inline int pci_write_config_word(const struct pci_dev *dev, int where, u16 val)
+{
+	return pci_bus_write_config_word(dev->bus, dev->devfn, where, val);
+}
+static inline int pci_write_config_dword(const struct pci_dev *dev, int where,
+					 u32 val)
+{
+	return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
+}
+
+void pci_set_master(struct pci_dev *dev);
+void pci_clear_master(struct pci_dev *dev);
+int pci_enable_device(struct pci_dev *dev);
+
+#endif /* LINUX_PCI_H */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
new file mode 100644
index 0000000..49e2954
--- /dev/null
+++ b/include/linux/pci_ids.h
@@ -0,0 +1,136 @@
+/*
+ *	PCI Class, Vendor and Device IDs
+ *
+ *	Please keep sorted.
+ *
+ *	Do not add new entries to this file unless the definitions
+ *	are shared between multiple drivers.
+ */
+
+/* Device classes and subclasses */
+
+#define PCI_CLASS_NOT_DEFINED		0x0000
+#define PCI_CLASS_NOT_DEFINED_VGA	0x0001
+
+#define PCI_BASE_CLASS_STORAGE		0x01
+#define PCI_CLASS_STORAGE_SCSI		0x0100
+#define PCI_CLASS_STORAGE_IDE		0x0101
+#define PCI_CLASS_STORAGE_FLOPPY	0x0102
+#define PCI_CLASS_STORAGE_IPI		0x0103
+#define PCI_CLASS_STORAGE_RAID		0x0104
+#define PCI_CLASS_STORAGE_SATA		0x0106
+#define PCI_CLASS_STORAGE_SATA_AHCI	0x010601
+#define PCI_CLASS_STORAGE_SAS		0x0107
+#define PCI_CLASS_STORAGE_OTHER		0x0180
+
+#define PCI_BASE_CLASS_NETWORK		0x02
+#define PCI_CLASS_NETWORK_ETHERNET	0x0200
+#define PCI_CLASS_NETWORK_TOKEN_RING	0x0201
+#define PCI_CLASS_NETWORK_FDDI		0x0202
+#define PCI_CLASS_NETWORK_ATM		0x0203
+#define PCI_CLASS_NETWORK_OTHER		0x0280
+
+#define PCI_BASE_CLASS_DISPLAY		0x03
+#define PCI_CLASS_DISPLAY_VGA		0x0300
+#define PCI_CLASS_DISPLAY_XGA		0x0301
+#define PCI_CLASS_DISPLAY_3D		0x0302
+#define PCI_CLASS_DISPLAY_OTHER		0x0380
+
+#define PCI_BASE_CLASS_MULTIMEDIA	0x04
+#define PCI_CLASS_MULTIMEDIA_VIDEO	0x0400
+#define PCI_CLASS_MULTIMEDIA_AUDIO	0x0401
+#define PCI_CLASS_MULTIMEDIA_PHONE	0x0402
+#define PCI_CLASS_MULTIMEDIA_OTHER	0x0480
+
+#define PCI_BASE_CLASS_MEMORY		0x05
+#define PCI_CLASS_MEMORY_RAM		0x0500
+#define PCI_CLASS_MEMORY_FLASH		0x0501
+#define PCI_CLASS_MEMORY_OTHER		0x0580
+
+#define PCI_BASE_CLASS_BRIDGE		0x06
+#define PCI_CLASS_BRIDGE_HOST		0x0600
+#define PCI_CLASS_BRIDGE_ISA		0x0601
+#define PCI_CLASS_BRIDGE_EISA		0x0602
+#define PCI_CLASS_BRIDGE_MC		0x0603
+#define PCI_CLASS_BRIDGE_PCI		0x0604
+#define PCI_CLASS_BRIDGE_PCMCIA		0x0605
+#define PCI_CLASS_BRIDGE_NUBUS		0x0606
+#define PCI_CLASS_BRIDGE_CARDBUS	0x0607
+#define PCI_CLASS_BRIDGE_RACEWAY	0x0608
+#define PCI_CLASS_BRIDGE_OTHER		0x0680
+
+#define PCI_BASE_CLASS_COMMUNICATION	0x07
+#define PCI_CLASS_COMMUNICATION_SERIAL	0x0700
+#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701
+#define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702
+#define PCI_CLASS_COMMUNICATION_MODEM	0x0703
+#define PCI_CLASS_COMMUNICATION_OTHER	0x0780
+
+#define PCI_BASE_CLASS_SYSTEM		0x08
+#define PCI_CLASS_SYSTEM_PIC		0x0800
+#define PCI_CLASS_SYSTEM_PIC_IOAPIC	0x080010
+#define PCI_CLASS_SYSTEM_PIC_IOXAPIC	0x080020
+#define PCI_CLASS_SYSTEM_DMA		0x0801
+#define PCI_CLASS_SYSTEM_TIMER		0x0802
+#define PCI_CLASS_SYSTEM_RTC		0x0803
+#define PCI_CLASS_SYSTEM_PCI_HOTPLUG	0x0804
+#define PCI_CLASS_SYSTEM_SDHCI		0x0805
+#define PCI_CLASS_SYSTEM_OTHER		0x0880
+
+#define PCI_BASE_CLASS_INPUT		0x09
+#define PCI_CLASS_INPUT_KEYBOARD	0x0900
+#define PCI_CLASS_INPUT_PEN		0x0901
+#define PCI_CLASS_INPUT_MOUSE		0x0902
+#define PCI_CLASS_INPUT_SCANNER		0x0903
+#define PCI_CLASS_INPUT_GAMEPORT	0x0904
+#define PCI_CLASS_INPUT_OTHER		0x0980
+
+#define PCI_BASE_CLASS_DOCKING		0x0a
+#define PCI_CLASS_DOCKING_GENERIC	0x0a00
+#define PCI_CLASS_DOCKING_OTHER		0x0a80
+
+#define PCI_BASE_CLASS_PROCESSOR	0x0b
+#define PCI_CLASS_PROCESSOR_386		0x0b00
+#define PCI_CLASS_PROCESSOR_486		0x0b01
+#define PCI_CLASS_PROCESSOR_PENTIUM	0x0b02
+#define PCI_CLASS_PROCESSOR_ALPHA	0x0b10
+#define PCI_CLASS_PROCESSOR_POWERPC	0x0b20
+#define PCI_CLASS_PROCESSOR_MIPS	0x0b30
+#define PCI_CLASS_PROCESSOR_CO		0x0b40
+
+#define PCI_BASE_CLASS_SERIAL		0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE	0x0c00
+#define PCI_CLASS_SERIAL_FIREWIRE_OHCI	0x0c0010
+#define PCI_CLASS_SERIAL_ACCESS		0x0c01
+#define PCI_CLASS_SERIAL_SSA		0x0c02
+#define PCI_CLASS_SERIAL_USB		0x0c03
+#define PCI_CLASS_SERIAL_USB_UHCI	0x0c0300
+#define PCI_CLASS_SERIAL_USB_OHCI	0x0c0310
+#define PCI_CLASS_SERIAL_USB_EHCI	0x0c0320
+#define PCI_CLASS_SERIAL_USB_XHCI	0x0c0330
+#define PCI_CLASS_SERIAL_FIBER		0x0c04
+#define PCI_CLASS_SERIAL_SMBUS		0x0c05
+
+#define PCI_BASE_CLASS_WIRELESS			0x0d
+#define PCI_CLASS_WIRELESS_RF_CONTROLLER	0x0d10
+#define PCI_CLASS_WIRELESS_WHCI			0x0d1010
+
+#define PCI_BASE_CLASS_INTELLIGENT	0x0e
+#define PCI_CLASS_INTELLIGENT_I2O	0x0e00
+
+#define PCI_BASE_CLASS_SATELLITE	0x0f
+#define PCI_CLASS_SATELLITE_TV		0x0f00
+#define PCI_CLASS_SATELLITE_AUDIO	0x0f01
+#define PCI_CLASS_SATELLITE_VOICE	0x0f03
+#define PCI_CLASS_SATELLITE_DATA	0x0f04
+
+#define PCI_BASE_CLASS_CRYPT		0x10
+#define PCI_CLASS_CRYPT_NETWORK		0x1000
+#define PCI_CLASS_CRYPT_ENTERTAINMENT	0x1001
+#define PCI_CLASS_CRYPT_OTHER		0x1080
+
+#define PCI_BASE_CLASS_SIGNAL_PROCESSING 0x11
+#define PCI_CLASS_SP_DPIO		0x1100
+#define PCI_CLASS_SP_OTHER		0x1180
+
+#define PCI_CLASS_OTHERS		0xff
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
new file mode 100644
index 0000000..14a3ed3
--- /dev/null
+++ b/include/linux/pci_regs.h
@@ -0,0 +1,110 @@
+/*
+ *	pci_regs.h
+ *
+ *	PCI standard defines
+ *	Copyright 1994, Drew Eckhardt
+ *	Copyright 1997--1999 Martin Mares <mj@ucw.cz>
+ *
+ *	For more information, please consult the following manuals (look at
+ *	http://www.pcisig.com/ for how to get them):
+ *
+ *	PCI BIOS Specification
+ *	PCI Local Bus Specification
+ *	PCI to PCI Bridge Specification
+ *	PCI System Design Guide
+ *
+ *	For HyperTransport information, please consult the following manuals
+ *	from http://www.hypertransport.org
+ *
+ *	The HyperTransport I/O Link Specification
+ */
+
+#ifndef LINUX_PCI_REGS_H
+#define LINUX_PCI_REGS_H
+
+/*
+ * Under PCI, each device has 256 bytes of configuration address space,
+ * of which the first 64 bytes are standardized as follows:
+ */
+#define PCI_VENDOR_ID		0x00	/* 16 bits */
+#define PCI_DEVICE_ID		0x02	/* 16 bits */
+#define PCI_COMMAND		0x04	/* 16 bits */
+#define  PCI_COMMAND_IO		0x1	/* Enable response in I/O space */
+#define  PCI_COMMAND_MEMORY	0x2	/* Enable response in Memory space */
+#define  PCI_COMMAND_MASTER	0x4	/* Enable bus mastering */
+#define  PCI_COMMAND_SPECIAL	0x8	/* Enable response to special cycles */
+#define  PCI_COMMAND_INVALIDATE	0x10	/* Use memory write and invalidate */
+#define  PCI_COMMAND_VGA_PALETTE 0x20	/* Enable palette snooping */
+#define  PCI_COMMAND_PARITY	0x40	/* Enable parity checking */
+#define  PCI_COMMAND_WAIT	0x80	/* Enable address/data stepping */
+#define  PCI_COMMAND_SERR	0x100	/* Enable SERR */
+#define  PCI_COMMAND_FAST_BACK	0x200	/* Enable back-to-back writes */
+#define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
+
+#define PCI_STATUS		0x06	/* 16 bits */
+#define  PCI_STATUS_INTERRUPT	0x08	/* Interrupt status */
+#define  PCI_STATUS_CAP_LIST	0x10	/* Support Capability List */
+#define  PCI_STATUS_66MHZ	0x20	/* Support 66 MHz PCI 2.1 bus */
+#define  PCI_STATUS_UDF		0x40	/* Support User Definable Features [obsolete] */
+#define  PCI_STATUS_FAST_BACK	0x80	/* Accept fast-back to back */
+#define  PCI_STATUS_PARITY	0x100	/* Detected parity error */
+#define  PCI_STATUS_DEVSEL_MASK	0x600	/* DEVSEL timing */
+#define  PCI_STATUS_DEVSEL_FAST		0x000
+#define  PCI_STATUS_DEVSEL_MEDIUM	0x200
+#define  PCI_STATUS_DEVSEL_SLOW		0x400
+#define  PCI_STATUS_SIG_TARGET_ABORT	0x800 /* Set on target abort */
+#define  PCI_STATUS_REC_TARGET_ABORT	0x1000 /* Master ack of " */
+#define  PCI_STATUS_REC_MASTER_ABORT	0x2000 /* Set on master abort */
+#define  PCI_STATUS_SIG_SYSTEM_ERROR	0x4000 /* Set when we drive SERR */
+#define  PCI_STATUS_DETECTED_PARITY	0x8000 /* Set on parity error */
+
+#define PCI_CLASS_REVISION	0x08	/* High 24 bits are class, low 8 revision */
+#define PCI_REVISION_ID		0x08	/* Revision ID */
+#define PCI_CLASS_PROG		0x09	/* Reg. Level Programming Interface */
+#define PCI_CLASS_DEVICE	0x0a	/* Device class */
+
+#define PCI_CACHE_LINE_SIZE	0x0c	/* 8 bits */
+#define PCI_LATENCY_TIMER	0x0d	/* 8 bits */
+#define PCI_HEADER_TYPE		0x0e	/* 8 bits */
+#define  PCI_HEADER_TYPE_NORMAL		0
+#define  PCI_HEADER_TYPE_BRIDGE		1
+#define  PCI_HEADER_TYPE_CARDBUS	2
+
+#define PCI_BIST		0x0f	/* 8 bits */
+#define  PCI_BIST_CODE_MASK	0x0f	/* Return result */
+#define  PCI_BIST_START		0x40	/* 1 to start BIST, 2 secs or less */
+#define  PCI_BIST_CAPABLE	0x80	/* 1 if BIST capable */
+
+/*
+ * Base addresses specify locations in memory or I/O space.
+ * Decoded size can be determined by writing a value of
+ * 0xffffffff to the register, and reading it back.  Only
+ * 1 bits are decoded.
+ */
+#define PCI_BASE_ADDRESS_0	0x10	/* 32 bits */
+#define PCI_BASE_ADDRESS_1	0x14	/* 32 bits [htype 0,1 only] */
+#define PCI_BASE_ADDRESS_2	0x18	/* 32 bits [htype 0 only] */
+#define PCI_BASE_ADDRESS_3	0x1c	/* 32 bits */
+#define PCI_BASE_ADDRESS_4	0x20	/* 32 bits */
+#define PCI_BASE_ADDRESS_5	0x24	/* 32 bits */
+#define  PCI_BASE_ADDRESS_SPACE		0x01	/* 0 = memory, 1 = I/O */
+#define  PCI_BASE_ADDRESS_SPACE_IO	0x01
+#define  PCI_BASE_ADDRESS_SPACE_MEMORY	0x00
+#define  PCI_BASE_ADDRESS_MEM_TYPE_MASK	0x06
+#define  PCI_BASE_ADDRESS_MEM_TYPE_32	0x00	/* 32 bit address */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_1M	0x02	/* Below 1M [obsolete] */
+#define  PCI_BASE_ADDRESS_MEM_TYPE_64	0x04	/* 64 bit address */
+#define  PCI_BASE_ADDRESS_MEM_PREFETCH	0x08	/* prefetchable? */
+#define  PCI_BASE_ADDRESS_MEM_MASK	(~0x0fUL)
+#define  PCI_BASE_ADDRESS_IO_MASK	(~0x03UL)
+/* bit 1 is reserved if address_space = 1 */
+
+/* Header type 0 (normal devices) */
+#define PCI_CARDBUS_CIS		0x28
+#define PCI_SUBSYSTEM_VENDOR_ID	0x2c
+#define PCI_SUBSYSTEM_ID	0x2e
+#define PCI_ROM_ADDRESS		0x30	/* Bits 31..11 are address, 10..1 reserved */
+#define  PCI_ROM_ADDRESS_ENABLE	0x01
+#define PCI_ROM_ADDRESS_MASK	(~0x7ffUL)
+
+#endif /* LINUX_PCI_REGS_H */
-- 
1.9.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v4 3/6] commands: add 'lspci' command
  2014-06-30 19:59 [RFC v4 0/6] barebox PCI support Antony Pavlov
  2014-06-30 19:59 ` [RFC v4 1/6] MIPS: add dma_alloc_coherent() Antony Pavlov
  2014-06-30 19:59 ` [RFC v4 2/6] PCI: initial commit Antony Pavlov
@ 2014-06-30 19:59 ` Antony Pavlov
  2014-06-30 19:59 ` [RFC v4 4/6] net: add RealTek RTL-8139 PCI Ethernet driver Antony Pavlov
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Antony Pavlov @ 2014-06-30 19:59 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 commands/Kconfig  |  8 ++++++++
 commands/Makefile |  1 +
 commands/lspci.c  | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 61 insertions(+)

diff --git a/commands/Kconfig b/commands/Kconfig
index eed6fbd..c98dbc5 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -207,6 +207,14 @@ config CMD_REGULATOR
 	  the regulator command lists the currently registered regulators and
 	  their current state.
 
+config CMD_LSPCI
+	bool
+	depends on PCI
+	prompt "lspci command"
+	default y
+	help
+	  The lspci command allows to list all PCI devices.
+
 config CMD_VERSION
 	tristate
 	default y
diff --git a/commands/Makefile b/commands/Makefile
index a84d333..d42aca5 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -99,3 +99,4 @@ obj-$(CONFIG_CMD_READF)		+= readf.o
 obj-$(CONFIG_CMD_MENUTREE)	+= menutree.o
 obj-$(CONFIG_CMD_2048)		+= 2048.o
 obj-$(CONFIG_CMD_REGULATOR)	+= regulator.o
+obj-$(CONFIG_CMD_LSPCI)		+= lspci.o
diff --git a/commands/lspci.c b/commands/lspci.c
new file mode 100644
index 0000000..c00b57f
--- /dev/null
+++ b/commands/lspci.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011-2014 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This file is part of barebox.
+ * See file CREDITS for list of people who contributed to this project.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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.
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <complete.h>
+#include <linux/pci.h>
+
+static int do_lspci(int argc, char *argv[])
+{
+	struct pci_bus *root_bus;
+	struct pci_dev *dev;
+
+	if (list_empty(&pci_root_buses)) {
+		printf("No PCI bus detected\n");
+		return 1;
+	}
+
+	list_for_each_entry(root_bus, &pci_root_buses, node) {
+		list_for_each_entry(dev, &root_bus->devices, bus_list) {
+			printf("%02x: %04x: %04x:%04x (rev %02x)\n",
+				      dev->devfn,
+				      (dev->class >> 8) & 0xffff,
+				      dev->vendor,
+				      dev->device,
+				      dev->revision);
+		}
+	}
+
+	return 0;
+}
+
+BAREBOX_CMD_START(lspci)
+	.cmd            = do_lspci,
+	BAREBOX_CMD_DESC("Show PCI info")
+	BAREBOX_CMD_GROUP(CMD_GRP_INFO)
+	BAREBOX_CMD_COMPLETE(empty_complete)
+BAREBOX_CMD_END
-- 
1.9.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v4 4/6] net: add RealTek RTL-8139 PCI Ethernet driver
  2014-06-30 19:59 [RFC v4 0/6] barebox PCI support Antony Pavlov
                   ` (2 preceding siblings ...)
  2014-06-30 19:59 ` [RFC v4 3/6] commands: add 'lspci' command Antony Pavlov
@ 2014-06-30 19:59 ` Antony Pavlov
  2014-07-02  6:18   ` Sascha Hauer
  2014-06-30 19:59 ` [RFC v4 5/6] MIPS: add PCI support for GT64120-based Malta board Antony Pavlov
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 10+ messages in thread
From: Antony Pavlov @ 2014-06-30 19:59 UTC (permalink / raw)
  To: barebox

This driver is based on Linux 2.6.39 8139too driver.

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 drivers/net/Kconfig     |   8 +
 drivers/net/Makefile    |   1 +
 drivers/net/rtl8139.c   | 616 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/pci_ids.h |   5 +
 4 files changed, 630 insertions(+)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 7a0d5e1..975c927 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -130,6 +130,14 @@ config DRIVER_NET_ORION
 	select PHYLIB
 	select MDIO_MVEBU
 
+config DRIVER_NET_RTL8139
+	bool "RealTek RTL-8139 PCI Ethernet driver"
+	depends on PCI
+	select PHYLIB
+	help
+	  This is a driver for the Fast Ethernet PCI network cards based on
+	  the RTL 8139 chips.
+
 config DRIVER_NET_SMC911X
 	bool "smc911x ethernet driver"
 	select PHYLIB
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 65f0d8b..d907061 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_DRIVER_NET_MICREL)		+= ksz8864rmn.o
 obj-$(CONFIG_DRIVER_NET_MPC5200)	+= fec_mpc5200.o
 obj-$(CONFIG_DRIVER_NET_NETX)		+= netx_eth.o
 obj-$(CONFIG_DRIVER_NET_ORION)		+= orion-gbe.o
+obj-$(CONFIG_DRIVER_NET_RTL8139)	+= rtl8139.o
 obj-$(CONFIG_DRIVER_NET_SMC911X)	+= smc911x.o
 obj-$(CONFIG_DRIVER_NET_SMC91111)	+= smc91111.o
 obj-$(CONFIG_DRIVER_NET_TAP)		+= tap.o
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
new file mode 100644
index 0000000..82c3585
--- /dev/null
+++ b/drivers/net/rtl8139.c
@@ -0,0 +1,616 @@
+#include <common.h>
+#include <net.h>
+#include <malloc.h>
+#include <init.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <io.h>
+#include <linux/phy.h>
+#include <linux/pci.h>
+
+#include <asm/dma-mapping.h>
+
+#define RTL8139_DEBUG
+#undef RTL8139_DEBUG
+
+/*
+ * Receive ring size
+ * Warning: 64K ring has hardware issues and may lock up.
+ */
+#define RX_BUF_IDX	0	/* 8K ring */
+#define RX_BUF_LEN	(8192 << RX_BUF_IDX)
+#define RX_BUF_PAD	16
+#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
+
+#if RX_BUF_LEN == 65536
+#define RX_BUF_TOT_LEN	RX_BUF_LEN
+#else
+#define RX_BUF_TOT_LEN	(RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
+#endif
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC	4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE	1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define TX_BUF_SIZE	MAX_ETH_FRAME_SIZE
+#define TX_BUF_TOT_LEN	(TX_BUF_SIZE * NUM_TX_DESC)
+
+/* PCI Tuning Parameters
+   Threshold is bytes transferred to chip before transmission starts. */
+#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH	7	/* Rx buffer level before first PCI xfer.  */
+#define RX_DMA_BURST	7	/* Maximum PCI burst, '6' is 1024 */
+#define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
+#define TX_RETRY	8	/* 0-15.  retries = 16 + (TX_RETRY * 16) */
+
+struct rtl8139_priv {
+	struct eth_device	edev;
+	void __iomem		*base;
+	struct pci_dev		*pci_dev;
+	unsigned char		*rx_ring;
+	unsigned int		cur_rx; /* RX buf index of next pkt */
+	dma_addr_t		rx_ring_dma;
+
+	u32			rx_config;
+	unsigned int		tx_flag;
+	unsigned long		cur_tx;
+	unsigned long		dirty_tx;
+	unsigned char		*tx_buf[NUM_TX_DESC];   /* Tx bounce buffers */
+	unsigned char		*tx_bufs;       /* Tx bounce buffer region. */
+	dma_addr_t		tx_bufs_dma;
+
+	struct mii_bus miibus;
+};
+
+#define ETH_ZLEN        60              /* Min. octets in frame sans FCS */
+
+/* Registers */
+#define MAC0		0x00
+#define MAR0		0x08
+#define TxStatus0	0x10
+
+enum TxStatusBits {
+	TxHostOwns	= 0x2000,
+	TxUnderrun	= 0x4000,
+	TxStatOK	= 0x8000,
+	TxOutOfWindow	= 0x20000000,
+	TxAborted	= 0x40000000,
+	TxCarrierLost	= 0x80000000,
+};
+
+#define TxAddr0		0x20
+#define RxBuf		0x30
+#define ChipCmd		0x37
+#define  CmdReset	0x10
+#define  CmdRxEnb	0x08
+#define  CmdTxEnb	0x04
+#define  RxBufEmpty	0x01
+#define RxBufPtr	0x38
+#define RxBufAddr	0x3A
+#define IntrMask	0x3C
+#define IntrStatus	0x3E
+#define  PCIErr		0x8000
+#define  PCSTimeout	0x4000
+#define  RxFIFOOver	0x0040
+#define  RxUnderrun	0x0020
+#define  RxOverflow	0x0010
+#define  TxErr		0x0008
+#define  TxOK		0x0004
+#define  RxErr		0x0002
+#define  RxOK		0x0001
+#define    RxAckBits	(RxFIFOOver | RxOverflow | RxOK)
+
+#define TxConfig	0x40
+/* Bits in TxConfig. */
+enum tx_config_bits {
+	/* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
+	TxIFGShift	= 24,
+	TxIFG84		= (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
+	TxIFG88		= (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
+	TxIFG92		= (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
+	TxIFG96		= (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
+
+	TxLoopBack	= (1 << 18) | (1 << 17), /* enable loopback test mode */
+	TxCRC		= (1 << 16),	/* DISABLE Tx pkt CRC append */
+	TxClearAbt	= (1 << 0),	/* Clear abort (WO) */
+	TxDMAShift	= 8, /* DMA burst value (0-7) is shifted X many bits */
+	TxRetryShift	= 4, /* TXRR value (0-15) is shifted X many bits */
+
+	TxVersionMask	= 0x7C800000, /* mask out version bits 30-26, 23 */
+};
+
+#define RxConfig	0x44
+	/* rx fifo threshold */
+#define  RxCfgFIFOShift	13
+#define	 RxCfgFIFONone	(7 << RxCfgFIFOShift)
+	/* Max DMA burst */
+#define	 RxCfgDMAShift	8
+#define	 RxCfgDMAUnlimited (7 << RxCfgDMAShift)
+	/* rx ring buffer length */
+#define	 RxCfgRcv8K	0
+#define	 RxCfgRcv16K	(1 << 11)
+#define	 RxCfgRcv32K	(1 << 12)
+#define	 RxCfgRcv64K	((1 << 11) | (1 << 12))
+	/* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
+#define	 RxNoWrap	(1 << 7)
+#define	 AcceptErr		0x20
+#define	 AcceptRunt		0x10
+#define	 AcceptBroadcast	0x08
+#define	 AcceptMulticast	0x04
+#define	 AcceptMyPhys		0x02
+#define	 AcceptAllPhys		0x01
+
+#define RxMissed	0x4C
+#define Cfg9346		0x50
+#define  Cfg9346_Lock	0x00
+#define  Cfg9346_Unlock	0xC0
+#define BasicModeCtrl	0x62
+#define BasicModeStatus	0x64
+#define NWayAdvert	0x66
+#define NWayLPAR	0x68
+#define NWayExpansion	0x6a
+
+static const char mii_2_8139_map[8] = {
+	BasicModeCtrl,
+	BasicModeStatus,
+	0,
+	0,
+	NWayAdvert,
+	NWayLPAR,
+	NWayExpansion,
+	0
+};
+
+/* write MMIO register */
+#define RTL_W8(priv, reg, val)	writeb(val, ((char *)(priv->base) + reg))
+#define RTL_W16(priv, reg, val)	writew(val, ((char *)(priv->base) + reg))
+#define RTL_W32(priv, reg, val)	writel(val, ((char *)(priv->base) + reg))
+
+/* read MMIO register */
+#define RTL_R8(priv, reg)	readb(((char *)(priv->base) + reg))
+#define RTL_R16(priv, reg)	readw(((char *)(priv->base) + reg))
+#define RTL_R32(priv, reg)	readl(((char *)(priv->base) + reg))
+
+/* write MMIO register, with flush */
+/* Flush avoids rtl8139 bug w/ posted MMIO writes */
+static inline void RTL_W8_F(struct rtl8139_priv *priv, int reg, int val)
+{
+	RTL_W8(priv, reg, val);
+	RTL_R8(priv, reg);
+}
+
+static inline void RTL_W16_F(struct rtl8139_priv *priv, int reg, int val)
+{
+	RTL_W16(priv, reg, val);
+	RTL_R16(priv, reg);
+}
+
+static inline void RTL_W32_F(struct rtl8139_priv *priv, int reg, int val)
+{
+	RTL_W32(priv, reg, val);
+	RTL_R32(priv, reg);
+}
+
+static const unsigned int rtl8139_rx_config =
+	RxCfgRcv8K | RxNoWrap |
+	(RX_FIFO_THRESH << RxCfgFIFOShift) |
+	(RX_DMA_BURST << RxCfgDMAShift);
+
+static const unsigned int rtl8139_tx_config =
+	TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
+
+static void rtl8139_chip_reset(struct rtl8139_priv *priv)
+{
+	int i;
+
+	/* Soft reset the chip. */
+	RTL_W8(priv, ChipCmd, CmdReset);
+
+	/* Check that the chip has finished the reset. */
+	for (i = 1000; i > 0; i--) {
+		if ((RTL_R8(priv, ChipCmd) & CmdReset) == 0)
+			break;
+		udelay(10);
+	}
+}
+
+static void __set_rx_mode(struct rtl8139_priv *priv)
+{
+	u32 mc_filter[2];	/* Multicast hash filter */
+	int rx_mode;
+	u32 tmp;
+
+	rx_mode =
+	    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+	    AcceptAllPhys;
+	mc_filter[1] = mc_filter[0] = 0xffffffff;
+
+	/* We can safely update without stopping the chip. */
+	tmp = rtl8139_rx_config | rx_mode;
+	if (priv->rx_config != tmp) {
+		RTL_W32_F(priv, RxConfig, tmp);
+		priv->rx_config = tmp;
+	}
+
+	RTL_W32_F(priv, MAR0 + 0, mc_filter[0]);
+	RTL_W32_F(priv, MAR0 + 4, mc_filter[1]);
+}
+
+/* Start the hardware at open or resume. */
+static void rtl8139_hw_start(struct rtl8139_priv *priv)
+{
+	u32 i;
+	u8 tmp;
+
+	rtl8139_chip_reset(priv);
+
+	/* unlock Config[01234] and BMCR register writes */
+	RTL_W8_F(priv, Cfg9346, Cfg9346_Unlock);
+
+	/* FIXME */
+#if 0
+	/* Restore our idea of the MAC address. */
+	RTL_W32_F(priv, MAC0 + 0, *(__le32 *) (dev->dev_addr + 0));
+	RTL_W32_F(priv, MAC0 + 4, *(__le16 *) (dev->dev_addr + 4));
+#endif
+
+	priv->cur_rx = 0;
+
+	/* init Rx ring buffer DMA address */
+	RTL_W32_F(priv, RxBuf, priv->rx_ring_dma);
+
+	/* Must enable Tx/Rx before setting transfer thresholds! */
+	RTL_W8(priv, ChipCmd, CmdRxEnb | CmdTxEnb);
+
+	priv->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
+	RTL_W32(priv, RxConfig, priv->rx_config);
+	RTL_W32(priv, TxConfig, rtl8139_tx_config);
+
+	/* Lock Config[01234] and BMCR register writes */
+	RTL_W8(priv, Cfg9346, Cfg9346_Lock);
+
+	/* init Tx buffer DMA addresses */
+	for (i = 0; i < NUM_TX_DESC; i++)
+		RTL_W32_F(priv, TxAddr0 + (i * 4), priv->tx_bufs_dma + (priv->tx_buf[i] - priv->tx_bufs));
+
+	RTL_W32(priv, RxMissed, 0);
+
+	__set_rx_mode(priv);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16(priv, IntrMask, 0);
+
+	/* make sure RxTx has started */
+	tmp = RTL_R8(priv, ChipCmd);
+	if ((!(tmp & CmdRxEnb)) || (!(tmp & CmdTxEnb)))
+		RTL_W8(priv, ChipCmd, CmdRxEnb | CmdTxEnb);
+}
+
+static inline void rtl8139_tx_clear(struct rtl8139_priv *priv)
+{
+	priv->cur_tx = 0;
+	priv->dirty_tx = 0;
+
+	/* XXX account for unsent Tx packets in tp->stats.tx_dropped */
+}
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void rtl8139_init_ring(struct rtl8139_priv *priv)
+{
+	int i;
+
+	priv->cur_rx = 0;
+	priv->cur_tx = 0;
+	priv->dirty_tx = 0;
+
+	for (i = 0; i < NUM_TX_DESC; i++)
+		priv->tx_buf[i] = &priv->tx_bufs[i * TX_BUF_SIZE];
+}
+
+static int rtl8139_phy_read(struct mii_bus *bus, int phy_addr, int reg)
+{
+	struct rtl8139_priv *priv = bus->priv;
+	int val;
+
+	val = 0xffff;
+
+	if (phy_addr == 0) { /* Really a 8139. Use internal registers. */
+		val = reg < 8 && mii_2_8139_map[reg] ?
+				RTL_R16(priv, mii_2_8139_map[reg]) : 0;
+	}
+
+	return val;
+}
+
+static int rtl8139_phy_write(struct mii_bus *bus, int phy_addr,
+	int reg, u16 val)
+{
+	struct rtl8139_priv *priv = bus->priv;
+
+	if (phy_addr == 0) { /* Really a 8139. Use internal registers. */
+		if (reg == 0) {
+			RTL_W8(priv, Cfg9346, Cfg9346_Unlock);
+			RTL_W16(priv, BasicModeCtrl, val);
+			RTL_W8(priv, Cfg9346, Cfg9346_Lock);
+		} else if (reg < 8 && mii_2_8139_map[reg]) {
+			RTL_W16(priv, mii_2_8139_map[reg], val);
+		}
+	}
+
+	return 0;
+}
+
+static int rtl8139_get_ethaddr(struct eth_device *edev, unsigned char *m)
+{
+	struct rtl8139_priv *priv = edev->priv;
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		m[i] = RTL_R8(priv, (MAC0 + i));
+	}
+
+	return 0;
+}
+
+static int rtl8139_set_ethaddr(struct eth_device *edev,
+					unsigned char *mac_addr)
+{
+	struct rtl8139_priv *priv = edev->priv;
+	int i;
+
+	RTL_W8(priv, Cfg9346, Cfg9346_Unlock);
+
+	for (i = 0; i < 6; i++) {
+		RTL_W8(priv, (MAC0 + i), mac_addr[i]);
+		RTL_R8(priv, mac_addr[i]);
+	}
+
+	RTL_W8(priv, Cfg9346, Cfg9346_Lock);
+
+	return 0;
+}
+
+static int rtl8139_init_dev(struct eth_device *edev)
+{
+	struct rtl8139_priv *priv = edev->priv;
+
+	rtl8139_chip_reset(priv);
+	pci_set_master(priv->pci_dev);
+
+	return 0;
+}
+
+static int rtl8139_eth_open(struct eth_device *edev)
+{
+	struct rtl8139_priv *priv = edev->priv;
+	int ret;
+
+	priv->tx_bufs = dma_alloc_coherent(TX_BUF_TOT_LEN, &priv->tx_bufs_dma);
+	priv->rx_ring = dma_alloc_coherent(RX_BUF_TOT_LEN, &priv->rx_ring_dma);
+	priv->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
+
+	rtl8139_init_ring(priv);
+	rtl8139_hw_start(priv);
+
+	ret = phy_device_connect(edev, &priv->miibus, 0, NULL, 0,
+				 PHY_INTERFACE_MODE_NA);
+
+	return ret;
+}
+
+static void rtl8139_eth_halt(struct eth_device *edev)
+{
+	struct rtl8139_priv *priv = edev->priv;
+
+	/* Stop the chip's Tx and Rx DMA processes. */
+	RTL_W8(priv, ChipCmd, 0);
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16(priv, IntrMask, 0);
+
+	pci_clear_master(priv->pci_dev);
+
+	/* Green! Put the chip in low-power mode. */
+	RTL_W8(priv, Cfg9346, Cfg9346_Unlock);
+}
+
+static void rtl8139_tx_interrupt(struct rtl8139_priv *priv)
+{
+	unsigned long dirty_tx, tx_left;
+
+	dirty_tx = priv->dirty_tx;
+	tx_left = priv->cur_tx - dirty_tx;
+	while (tx_left > 0) {
+		int entry = dirty_tx % NUM_TX_DESC;
+		int txstatus;
+
+		txstatus = RTL_R32(priv, TxStatus0 + (entry * sizeof(u32)));
+
+		if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
+			break;	/* It still hasn't been Txed */
+
+		/* Note: TxCarrierLost is always asserted at 100mbps. */
+		if (txstatus & (TxOutOfWindow | TxAborted)) {
+			/* There was an major error, log it. */
+			printk("Transmit error, Tx status %08x\n", txstatus);
+			if (txstatus & TxAborted) {
+				RTL_W32(priv, TxConfig, TxClearAbt);
+				RTL_W16(priv, IntrStatus, TxErr);
+			}
+		} else {
+			if (txstatus & TxUnderrun) {
+				/* Add 64 to the Tx FIFO threshold. */
+				if (priv->tx_flag < 0x00300000)
+					priv->tx_flag += 0x00020000;
+			}
+		}
+
+		dirty_tx++;
+		tx_left--;
+	}
+
+	if (priv->dirty_tx != dirty_tx) {
+		priv->dirty_tx = dirty_tx;
+	}
+}
+
+static int rtl8139_eth_send(struct eth_device *edev, void *packet,
+				int packet_length)
+{
+	struct rtl8139_priv *priv = edev->priv;
+
+	unsigned int entry;
+
+	rtl8139_tx_interrupt(priv);
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = priv->cur_tx % NUM_TX_DESC;
+
+	/* Note: the chip doesn't have auto-pad! */
+	if (likely(packet_length < TX_BUF_SIZE)) {
+		if (packet_length < ETH_ZLEN)
+			memset(priv->tx_buf[entry], 0, ETH_ZLEN);
+		memcpy(priv->tx_buf[entry], packet, packet_length);
+	} else {
+		printk("packet too long\n");
+		return 0;
+	}
+
+	/*
+	 * Writing to TxStatus triggers a DMA transfer of the data
+	 * copied to tp->tx_buf[entry] above.
+	 */
+	if (packet_length < ETH_ZLEN) {
+		packet_length = ETH_ZLEN;
+	}
+	RTL_W32_F(priv, (TxStatus0 + (entry * sizeof(u32))),
+			(priv->tx_flag | packet_length));
+
+	priv->cur_tx++;
+
+	return 0;
+}
+
+static const u16 rtl8139_intr_mask =
+		PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
+		TxErr | TxOK | RxErr | RxOK;
+
+static int rtl8139_eth_rx(struct eth_device *edev)
+{
+	struct rtl8139_priv *priv = edev->priv;
+	unsigned char *rx_ring = priv->rx_ring;
+	unsigned int cur_rx = priv->cur_rx;
+	unsigned int rx_size = 0;
+
+	u32 ring_offset = cur_rx % RX_BUF_LEN;
+	u32 rx_status;
+	unsigned int pkt_size;
+
+	rtl8139_tx_interrupt(priv);
+
+	if (RTL_R8(priv, ChipCmd) & RxBufEmpty) {
+		/* no data */
+		return 0;
+	}
+
+	rx_status = le32_to_cpu(*(__le32 *) (rx_ring + ring_offset));
+	rx_size = rx_status >> 16;
+	pkt_size = rx_size - 4;
+
+	net_receive(edev, &rx_ring[ring_offset + 4], pkt_size);
+
+	cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
+	cur_rx = cur_rx & (RX_BUF_LEN - 1); /* FIXME */
+	RTL_W16(priv, RxBufPtr, (u16) (cur_rx - 16));
+
+	priv->cur_rx = cur_rx;
+
+	return pkt_size /* size */;
+}
+
+static int rtl8139_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct eth_device *edev;
+	struct rtl8139_priv *priv;
+	int ret;
+	u32 bar;
+	struct pci_bus *bus = pdev->bus;
+	struct device_d *dev = &pdev->dev;
+
+	/* enable pci device */
+	pci_enable_device(pdev);
+
+	priv = xzalloc(sizeof(struct rtl8139_priv));
+
+	edev = &priv->edev;
+	dev->type_data = edev;
+	edev->priv = priv;
+
+	priv->pci_dev = pdev;
+
+	priv->miibus.read = rtl8139_phy_read;
+	priv->miibus.write = rtl8139_phy_write;
+	priv->miibus.priv = priv;
+	priv->miibus.parent = &edev->dev;
+
+	/* FIXME: pci_resource_start() */
+	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &bar);
+
+	/* FIXME: use pci_iomap() */
+	priv->base = (void *)bus->ops->res_start(bus, bar);
+
+	printk("found rtl8139 (rev %02x) at %02x: %04x (base=%p)\n",
+			pdev->revision,
+			pdev->devfn,
+			(pdev->class >> 8) & 0xffff,
+			priv->base);
+
+	edev->init = rtl8139_init_dev;
+	edev->open = rtl8139_eth_open;
+	edev->send = rtl8139_eth_send;
+	edev->recv = rtl8139_eth_rx;
+	edev->get_ethaddr = rtl8139_get_ethaddr;
+	edev->set_ethaddr = rtl8139_set_ethaddr;
+	edev->halt = rtl8139_eth_halt;
+	edev->parent = dev;
+
+	ret = eth_register(edev);
+	if (ret)
+		goto eth_err;
+
+	ret = mdiobus_register(&priv->miibus);
+	if (ret)
+		goto mdio_err;
+
+	return 0;
+
+mdio_err:
+	eth_unregister(edev);
+
+eth_err:
+	free(priv);
+
+	return ret;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(rtl8139_pci_tbl) = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK,	PCI_DEVICE_ID_REALTEK_8139), },
+	{ },
+};
+
+static struct pci_driver rtl8139_eth_driver = {
+	.name = "rtl8139_eth",
+	.id_table = rtl8139_pci_tbl,
+	.probe = rtl8139_probe,
+};
+
+static int rtl8139_init(void)
+{
+	return pci_register_driver(&rtl8139_eth_driver);
+}
+device_initcall(rtl8139_init);
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 49e2954..17ac7fd 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -134,3 +134,8 @@
 #define PCI_CLASS_SP_OTHER		0x1180
 
 #define PCI_CLASS_OTHERS		0xff
+
+/* Vendors and devices.  Sort key: vendor first, device next. */
+
+#define PCI_VENDOR_ID_REALTEK		0x10ec
+#define PCI_DEVICE_ID_REALTEK_8139	0x8139
-- 
1.9.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v4 5/6] MIPS: add PCI support for GT64120-based Malta board
  2014-06-30 19:59 [RFC v4 0/6] barebox PCI support Antony Pavlov
                   ` (3 preceding siblings ...)
  2014-06-30 19:59 ` [RFC v4 4/6] net: add RealTek RTL-8139 PCI Ethernet driver Antony Pavlov
@ 2014-06-30 19:59 ` Antony Pavlov
  2014-06-30 19:59 ` [RFC v4 6/6] MIPS: qemu-malta_defconfig: enable PCI & network stuff Antony Pavlov
  2014-07-02  6:05 ` [RFC v4 0/6] barebox PCI support Sascha Hauer
  6 siblings, 0 replies; 10+ messages in thread
From: Antony Pavlov @ 2014-06-30 19:59 UTC (permalink / raw)
  To: barebox

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 arch/mips/Kconfig                                |   1 +
 arch/mips/include/asm/gt64120.h                  |  53 +++++
 arch/mips/mach-malta/Makefile                    |   1 +
 arch/mips/mach-malta/include/mach/mach-gt64120.h |   2 +
 arch/mips/mach-malta/pci.c                       | 236 +++++++++++++++++++++++
 5 files changed, 293 insertions(+)

diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index d4e9e1c..bc68c67 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -45,6 +45,7 @@ config MACH_MIPS_MALTA
 	select SYS_SUPPORTS_BIG_ENDIAN
 	select HAS_DEBUG_LL
 	select GPIOLIB
+	select HW_HAS_PCI
 
 config MACH_MIPS_AR231X
 	bool "Atheros ar231x-based boards"
diff --git a/arch/mips/include/asm/gt64120.h b/arch/mips/include/asm/gt64120.h
index 6b2ad0f..7e783c8 100644
--- a/arch/mips/include/asm/gt64120.h
+++ b/arch/mips/include/asm/gt64120.h
@@ -18,6 +18,8 @@
 #ifndef _ASM_GT64120_H
 #define _ASM_GT64120_H
 
+#define MSK(n)			((1 << (n)) - 1)
+
 #define GT_DEF_BASE		0x14000000
 
 /*
@@ -34,4 +36,55 @@
 #define GT_PCI0M1LD_OFS		0x080
 #define GT_PCI0M1HD_OFS		0x088
 
+#define GT_PCI0IOREMAP_OFS	0x0f0
+#define GT_PCI0M0REMAP_OFS	0x0f8
+#define GT_PCI0M1REMAP_OFS	0x100
+
+/* Interrupts.	*/
+#define GT_INTRCAUSE_OFS	0xc18
+
+/* PCI Internal.  */
+#define GT_PCI0_CMD_OFS		0xc00
+#define GT_PCI0_CFGADDR_OFS	0xcf8
+#define GT_PCI0_CFGDATA_OFS	0xcfc
+
+#define GT_PCI_DCRM_SHF		21
+#define GT_PCI_LD_SHF		0
+#define GT_PCI_LD_MSK		(MSK(15) << GT_PCI_LD_SHF)
+#define GT_PCI_HD_SHF		0
+#define GT_PCI_HD_MSK		(MSK(7) << GT_PCI_HD_SHF)
+#define GT_PCI_REMAP_SHF	0
+#define GT_PCI_REMAP_MSK	(MSK(11) << GT_PCI_REMAP_SHF)
+
+#define GT_INTRCAUSE_MASABORT0_SHF	18
+#define GT_INTRCAUSE_MASABORT0_MSK	(MSK(1) << GT_INTRCAUSE_MASABORT0_SHF)
+#define GT_INTRCAUSE_MASABORT0_BIT	GT_INTRCAUSE_MASABORT0_MSK
+
+#define GT_INTRCAUSE_TARABORT0_SHF	19
+#define GT_INTRCAUSE_TARABORT0_MSK	(MSK(1) << GT_INTRCAUSE_TARABORT0_SHF)
+#define GT_INTRCAUSE_TARABORT0_BIT	GT_INTRCAUSE_TARABORT0_MSK
+
+#define GT_PCI0_CFGADDR_REGNUM_SHF	2
+#define GT_PCI0_CFGADDR_REGNUM_MSK	(MSK(6) << GT_PCI0_CFGADDR_REGNUM_SHF)
+#define GT_PCI0_CFGADDR_FUNCTNUM_SHF	8
+#define GT_PCI0_CFGADDR_FUNCTNUM_MSK	(MSK(3) << GT_PCI0_CFGADDR_FUNCTNUM_SHF)
+#define GT_PCI0_CFGADDR_DEVNUM_SHF	11
+#define GT_PCI0_CFGADDR_DEVNUM_MSK	(MSK(5) << GT_PCI0_CFGADDR_DEVNUM_SHF)
+#define GT_PCI0_CFGADDR_BUSNUM_SHF	16
+#define GT_PCI0_CFGADDR_BUSNUM_MSK	(MSK(8) << GT_PCI0_CFGADDR_BUSNUM_SHF)
+#define GT_PCI0_CFGADDR_CONFIGEN_SHF	31
+#define GT_PCI0_CFGADDR_CONFIGEN_MSK	(MSK(1) << GT_PCI0_CFGADDR_CONFIGEN_SHF)
+#define GT_PCI0_CFGADDR_CONFIGEN_BIT	GT_PCI0_CFGADDR_CONFIGEN_MSK
+
+/*
+ * Because of an error/peculiarity in the Galileo chip, we need to swap the
+ * bytes when running bigendian.  We also provide non-swapping versions.
+ */
+#define __GT_READ(ofs)							\
+	(*(volatile u32 *)(GT64120_BASE+(ofs)))
+#define __GT_WRITE(ofs, data)						\
+	do { *(volatile u32 *)(GT64120_BASE+(ofs)) = (data); } while (0)
+#define GT_READ(ofs)		le32_to_cpu(__GT_READ(ofs))
+#define GT_WRITE(ofs, data)	__GT_WRITE(ofs, cpu_to_le32(data))
+
 #endif /* _ASM_GT64120_H */
diff --git a/arch/mips/mach-malta/Makefile b/arch/mips/mach-malta/Makefile
index f3cc668..0c5a701 100644
--- a/arch/mips/mach-malta/Makefile
+++ b/arch/mips/mach-malta/Makefile
@@ -1 +1,2 @@
 obj-y += reset.o
+obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/mips/mach-malta/include/mach/mach-gt64120.h b/arch/mips/mach-malta/include/mach/mach-gt64120.h
index ed1e23e..8f20fcf 100644
--- a/arch/mips/mach-malta/include/mach/mach-gt64120.h
+++ b/arch/mips/mach-malta/include/mach/mach-gt64120.h
@@ -10,4 +10,6 @@
 
 #define MIPS_GT_BASE	0x1be00000
 
+#define GT64120_BASE    0xbbe00000
+
 #endif /* _ASM_MACH_MIPS_MACH_GT64120_DEP_H */
diff --git a/arch/mips/mach-malta/pci.c b/arch/mips/mach-malta/pci.c
new file mode 100644
index 0000000..9035175
--- /dev/null
+++ b/arch/mips/mach-malta/pci.c
@@ -0,0 +1,236 @@
+#include <common.h>
+#include <types.h>
+#include <driver.h>
+#include <init.h>
+#include <mach/hardware.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+
+#include <linux/pci.h>
+#include <asm/gt64120.h>
+
+#include <mach/mach-gt64120.h>
+
+#define PCI_ACCESS_READ  0
+#define PCI_ACCESS_WRITE 1
+
+static struct resource gt64120_mem_resource = {
+	.name	= "GT-64120 PCI MEM",
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct resource gt64120_io_resource = {
+	.name	= "GT-64120 PCI I/O",
+	.flags	= IORESOURCE_IO,
+};
+
+static int gt64xxx_pci0_pcibios_config_access(unsigned char access_type,
+		struct pci_bus *bus, unsigned int devfn, int where, u32 *data)
+{
+	unsigned char busnum = bus->number;
+	u32 intr;
+
+	if ((busnum == 0) && (devfn >= PCI_DEVFN(31, 0)))
+		return -1;	/* Because of a bug in the galileo (for slot 31). */
+
+	/* Clear cause register bits */
+	GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+					GT_INTRCAUSE_TARABORT0_BIT));
+
+	/* Setup address */
+	GT_WRITE(GT_PCI0_CFGADDR_OFS,
+		 (busnum << GT_PCI0_CFGADDR_BUSNUM_SHF) |
+		 (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
+		 ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
+		 GT_PCI0_CFGADDR_CONFIGEN_BIT);
+
+	if (access_type == PCI_ACCESS_WRITE) {
+		if (busnum == 0 && PCI_SLOT(devfn) == 0) {
+			/*
+			 * The Galileo system controller is acting
+			 * differently than other devices.
+			 */
+			GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+		} else
+			__GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
+	} else {
+		if (busnum == 0 && PCI_SLOT(devfn) == 0) {
+			/*
+			 * The Galileo system controller is acting
+			 * differently than other devices.
+			 */
+			*data = GT_READ(GT_PCI0_CFGDATA_OFS);
+		} else
+			*data = __GT_READ(GT_PCI0_CFGDATA_OFS);
+	}
+
+	/* Check for master or target abort */
+	intr = GT_READ(GT_INTRCAUSE_OFS);
+
+	if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
+		/* Error occurred */
+
+		/* Clear bits */
+		GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
+						GT_INTRCAUSE_TARABORT0_BIT));
+
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * We can't address 8 and 16 bit words directly. Instead we have to
+ * read/write a 32bit word and mask/modify the data we actually want.
+ */
+static int gt64xxx_pci0_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+		int where, int size, u32 *val)
+{
+	u32 data = 0;
+
+	if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus, devfn,
+						where, &data))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (size == 1)
+		*val = (data >> ((where & 3) << 3)) & 0xff;
+	else if (size == 2)
+		*val = (data >> ((where & 3) << 3)) & 0xffff;
+	else
+		*val = data;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int gt64xxx_pci0_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+		int where, int size, u32 val)
+{
+	u32 data = 0;
+
+	if (size == 4)
+		data = val;
+	else {
+		if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_READ, bus,
+							devfn, where, &data))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+		if (size == 1)
+			data = (data & ~(0xff << ((where & 3) << 3))) |
+				(val << ((where & 3) << 3));
+		else if (size == 2)
+			data = (data & ~(0xffff << ((where & 3) << 3))) |
+				(val << ((where & 3) << 3));
+	}
+
+	if (gt64xxx_pci0_pcibios_config_access(PCI_ACCESS_WRITE, bus, devfn,
+						where, &data))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+/* function returns memory address for begin of pci resource */
+static int gt64xxx_res_start(struct pci_bus *bus, resource_size_t res_addr)
+{
+	return KSEG0ADDR(res_addr);
+}
+
+struct pci_ops gt64xxx_pci0_ops = {
+	.read	= gt64xxx_pci0_pcibios_read,
+	.write	= gt64xxx_pci0_pcibios_write,
+
+	.res_start = gt64xxx_res_start,
+};
+
+static struct pci_controller gt64120_controller = {
+	.pci_ops	= &gt64xxx_pci0_ops,
+	.io_resource	= &gt64120_io_resource,
+	.mem_resource	= &gt64120_mem_resource,
+};
+
+static int pcibios_init(void)
+{
+	resource_size_t start, end, map, start1, end1, map1, mask, res_end;
+
+	/*
+	 * Due to a bug in the Galileo system controller, we need
+	 * to setup the PCI BAR for the Galileo internal registers.
+	 * This should be done in the bios/bootprom and will be
+	 * fixed in a later revision of YAMON (the MIPS boards
+	 * boot prom).
+	 */
+	GT_WRITE(GT_PCI0_CFGADDR_OFS,
+		 (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) | /* Local bus */
+		 (0 << GT_PCI0_CFGADDR_DEVNUM_SHF) | /* GT64120 dev */
+		 (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) | /* Function 0*/
+		 ((0x20/4) << GT_PCI0_CFGADDR_REGNUM_SHF) | /* BAR 4*/
+		 GT_PCI0_CFGADDR_CONFIGEN_BIT);
+
+	/* Perform the write */
+	GT_WRITE(GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE));
+
+	/* Here is linux code. It assumes, that firmware
+	(pbl in case of barebox) made the work... */
+
+	/* Set up resource ranges from the controller's registers. */
+	start = GT_READ(GT_PCI0M0LD_OFS);
+	end = GT_READ(GT_PCI0M0HD_OFS);
+	map = GT_READ(GT_PCI0M0REMAP_OFS);
+	end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
+	start1 = GT_READ(GT_PCI0M1LD_OFS);
+	end1 = GT_READ(GT_PCI0M1HD_OFS);
+	map1 = GT_READ(GT_PCI0M1REMAP_OFS);
+	end1 = (end1 & GT_PCI_HD_MSK) | (start1 & ~GT_PCI_HD_MSK);
+
+	mask = ~(start ^ end);
+
+	/* We don't support remapping with a discontiguous mask. */
+	BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
+		mask != ~((mask & -mask) - 1));
+	gt64120_mem_resource.start = start;
+	gt64120_mem_resource.end = end;
+	gt64120_controller.mem_offset = (start & mask) - (map & mask);
+	/* Addresses are 36-bit, so do shifts in the destinations. */
+	gt64120_mem_resource.start <<= GT_PCI_DCRM_SHF;
+	gt64120_mem_resource.end <<= GT_PCI_DCRM_SHF;
+	gt64120_mem_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
+	gt64120_controller.mem_offset <<= GT_PCI_DCRM_SHF;
+
+	start = GT_READ(GT_PCI0IOLD_OFS);
+	end = GT_READ(GT_PCI0IOHD_OFS);
+	map = GT_READ(GT_PCI0IOREMAP_OFS);
+	end = (end & GT_PCI_HD_MSK) | (start & ~GT_PCI_HD_MSK);
+	mask = ~(start ^ end);
+
+	/* We don't support remapping with a discontiguous mask. */
+	BUG_ON((start & GT_PCI_HD_MSK) != (map & GT_PCI_HD_MSK) &&
+		mask != ~((mask & -mask) - 1));
+	gt64120_io_resource.start = map & mask;
+	res_end = (map & mask) | ~mask;
+	gt64120_controller.io_offset = 0;
+	/* Addresses are 36-bit, so do shifts in the destinations. */
+	gt64120_io_resource.start <<= GT_PCI_DCRM_SHF;
+	gt64120_io_resource.end <<= GT_PCI_DCRM_SHF;
+	gt64120_io_resource.end |= (1 << GT_PCI_DCRM_SHF) - 1;
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+	GT_WRITE(GT_PCI0_CMD_OFS, GT_PCI0_CMD_MBYTESWAP_BIT |
+		GT_PCI0_CMD_SBYTESWAP_BIT);
+#else
+	GT_WRITE(GT_PCI0_CMD_OFS, 0);
+#endif
+
+	/* Fix up PCI I/O mapping if necessary (for Atlas). */
+	start = GT_READ(GT_PCI0IOLD_OFS);
+	map = GT_READ(GT_PCI0IOREMAP_OFS);
+	if ((start & map) != 0) {
+		map &= ~start;
+		GT_WRITE(GT_PCI0IOREMAP_OFS, map);
+	}
+
+	register_pci_controller(&gt64120_controller);
+
+	return 0;
+}
+postcore_initcall(pcibios_init);
-- 
1.9.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC v4 6/6] MIPS: qemu-malta_defconfig: enable PCI & network stuff
  2014-06-30 19:59 [RFC v4 0/6] barebox PCI support Antony Pavlov
                   ` (4 preceding siblings ...)
  2014-06-30 19:59 ` [RFC v4 5/6] MIPS: add PCI support for GT64120-based Malta board Antony Pavlov
@ 2014-06-30 19:59 ` Antony Pavlov
  2014-07-02  6:05 ` [RFC v4 0/6] barebox PCI support Sascha Hauer
  6 siblings, 0 replies; 10+ messages in thread
From: Antony Pavlov @ 2014-06-30 19:59 UTC (permalink / raw)
  To: barebox

qemu usage:

  # ifconfig br0:1 172.20.0.1
  # qemu-system-mips -nodefaults -nographic -M malta -m 256 \
    -serial stdio -monitor null \
    -bios ./barebox-flash-image \
    -net nic,vlan=0,model=rtl8139 \
    -net tap,vlan=0,script=net_br0.sh

  ...

  barebox:/ eth0.ipaddr=172.20.0.2
  barebox:/ eth0.serverip=172.20.0.1
  barebox:/ ping 172.20.0.1
  phy0: Link is up - 100/Full
  host 172.20.0.1 is alive
  barebox:/

Sample net_br0.sh (for connecting to br0 interface, so you can
connect barebox to your real network):

  #!/bin/sh

  brctl addif br0 $1
  ifconfig $1 up

Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
 arch/mips/configs/qemu-malta_defconfig | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/mips/configs/qemu-malta_defconfig b/arch/mips/configs/qemu-malta_defconfig
index 78f175d..6ee302d 100644
--- a/arch/mips/configs/qemu-malta_defconfig
+++ b/arch/mips/configs/qemu-malta_defconfig
@@ -32,6 +32,7 @@ CONFIG_CMD_UNCOMPRESS=y
 CONFIG_CMD_GETOPT=y
 CONFIG_CMD_SLEEP=y
 CONFIG_CMD_DHCP=y
+CONFIG_CMD_MIITOOL=y
 CONFIG_CMD_PING=y
 CONFIG_CMD_TFTP=y
 CONFIG_CMD_ECHO_E=y
@@ -56,6 +57,7 @@ CONFIG_NET_NETCONSOLE=y
 CONFIG_NET_RESOLV=y
 CONFIG_OFDEVICE=y
 CONFIG_OF_BAREBOX_DRIVERS=y
+CONFIG_DRIVER_NET_RTL8139=y
 # CONFIG_SPI is not set
 CONFIG_I2C=y
 CONFIG_I2C_GPIO=y
@@ -66,6 +68,8 @@ CONFIG_DRIVER_CFI=y
 # CONFIG_DRIVER_CFI_BANK_WIDTH_2 is not set
 CONFIG_CFI_BUFFER_WRITE=y
 CONFIG_GPIO_MALTA_FPGA_I2C=y
+CONFIG_PCI=y
+CONFIG_PCI_DEBUG=y
 CONFIG_FS_CRAMFS=y
 CONFIG_FS_TFTP=y
 CONFIG_FS_FAT=y
-- 
1.9.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC v4 0/6] barebox PCI support
  2014-06-30 19:59 [RFC v4 0/6] barebox PCI support Antony Pavlov
                   ` (5 preceding siblings ...)
  2014-06-30 19:59 ` [RFC v4 6/6] MIPS: qemu-malta_defconfig: enable PCI & network stuff Antony Pavlov
@ 2014-07-02  6:05 ` Sascha Hauer
  6 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2014-07-02  6:05 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

Hi Antony,

I have some minor stuff to fix, but otherwise it looks good and Lukas
also indicated he is fine with this series. So it's time to remove the
RFC tag and to apply this series.

Sascha

On Mon, Jun 30, 2014 at 11:59:43PM +0400, Antony Pavlov wrote:
> This patchseries introduce simple PCI bus support for barebox.
> 
> Changes since RFC v3:
> 
>   * rebase over latest 'next';
>   * use list for pci_root_buses;
>   * move common PCI Kconfig stuff from arch/mips to drivers/pci;
>   * make pci_*_write_config_* PCIe-friendly (use 'int' type for
>     config register address);
>   * drop some unused stuff;
>   * change lspci "no pci" error message to "No PCI bus detected";
>   * rtl8139: use dma_alloc_coherent();
>   * rtl8139: use pci_set_master() & pci_clear_master().
> 
> TODOs for RFC v3:
> 
>   * no PCI bridges support;
>   * introduce pci_resource_start();
>   * introduce pci_iomap();
>   * clean '#if 0'.
> 
> This patchseries can be found on github:
> 
>   https://github.com/frantony/barebox/tree/pci.20140630
> 
> Antony Pavlov (6):
>   MIPS: add dma_alloc_coherent()
>   PCI: initial commit
>   commands: add 'lspci' command
>   net: add RealTek RTL-8139 PCI Ethernet driver
>   MIPS: add PCI support for GT64120-based Malta board
>   MIPS: qemu-malta_defconfig: enable PCI & network stuff
> 
>  arch/mips/Kconfig                                |   1 +
>  arch/mips/configs/qemu-malta_defconfig           |   4 +
>  arch/mips/include/asm/dma-mapping.h              |  25 +
>  arch/mips/include/asm/gt64120.h                  |  53 ++
>  arch/mips/mach-malta/Makefile                    |   1 +
>  arch/mips/mach-malta/include/mach/mach-gt64120.h |   2 +
>  arch/mips/mach-malta/pci.c                       | 236 +++++++++
>  commands/Kconfig                                 |   8 +
>  commands/Makefile                                |   1 +
>  commands/lspci.c                                 |  52 ++
>  drivers/Kconfig                                  |   1 +
>  drivers/Makefile                                 |   1 +
>  drivers/net/Kconfig                              |   8 +
>  drivers/net/Makefile                             |   1 +
>  drivers/net/rtl8139.c                            | 616 +++++++++++++++++++++++
>  drivers/pci/Kconfig                              |  29 ++
>  drivers/pci/Makefile                             |   8 +
>  drivers/pci/bus.c                                | 110 ++++
>  drivers/pci/pci.c                                | 285 +++++++++++
>  include/linux/mod_devicetable.h                  |  20 +
>  include/linux/pci.h                              | 292 +++++++++++
>  include/linux/pci_ids.h                          | 141 ++++++
>  include/linux/pci_regs.h                         | 110 ++++
>  23 files changed, 2005 insertions(+)
>  create mode 100644 arch/mips/include/asm/dma-mapping.h
>  create mode 100644 arch/mips/mach-malta/pci.c
>  create mode 100644 commands/lspci.c
>  create mode 100644 drivers/net/rtl8139.c
>  create mode 100644 drivers/pci/Kconfig
>  create mode 100644 drivers/pci/Makefile
>  create mode 100644 drivers/pci/bus.c
>  create mode 100644 drivers/pci/pci.c
>  create mode 100644 include/linux/mod_devicetable.h
>  create mode 100644 include/linux/pci.h
>  create mode 100644 include/linux/pci_ids.h
>  create mode 100644 include/linux/pci_regs.h
> 
> -- 
> 1.9.2
> 
> 

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC v4 2/6] PCI: initial commit
  2014-06-30 19:59 ` [RFC v4 2/6] PCI: initial commit Antony Pavlov
@ 2014-07-02  6:12   ` Sascha Hauer
  0 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2014-07-02  6:12 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

On Mon, Jun 30, 2014 at 11:59:45PM +0400, Antony Pavlov wrote:
> used shorten version of linux-2.6.39 pci_ids.h
> 
> Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> ---
>  drivers/Kconfig                 |   1 +
>  drivers/Makefile                |   1 +
>  drivers/pci/Kconfig             |  29 ++++
>  drivers/pci/Makefile            |   8 ++
>  drivers/pci/bus.c               | 110 +++++++++++++++
>  drivers/pci/pci.c               | 285 +++++++++++++++++++++++++++++++++++++++
>  include/linux/mod_devicetable.h |  20 +++
>  include/linux/pci.h             | 292 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci_ids.h         | 136 +++++++++++++++++++
>  include/linux/pci_regs.h        | 110 +++++++++++++++
>  10 files changed, 992 insertions(+)
> 
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index 53e1e97..12a9d8c 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -27,5 +27,6 @@ source "drivers/pinctrl/Kconfig"
>  source "drivers/bus/Kconfig"
>  source "drivers/regulator/Kconfig"
>  source "drivers/reset/Kconfig"
> +source "drivers/pci/Kconfig"
>  
>  endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index ef3604f..1990e86 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -26,3 +26,4 @@ obj-y += pinctrl/
>  obj-y += bus/
>  obj-$(CONFIG_REGULATOR) += regulator/
>  obj-$(CONFIG_RESET_CONTROLLER) += reset/
> +obj-$(CONFIG_PCI) += pci/
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> new file mode 100644
> index 0000000..9e46592
> --- /dev/null
> +++ b/drivers/pci/Kconfig
> @@ -0,0 +1,29 @@
> +config HW_HAS_PCI
> +	bool
> +
> +if HW_HAS_PCI
> +
> +menu "PCI bus options"
> +
> +config PCI
> +	bool "Support for PCI controller"
> +	depends on HW_HAS_PCI
> +	help
> +	  Find out whether you have a PCI motherboard. PCI is the name of a
> +	  bus system, i.e. the way the CPU talks to the other stuff inside
> +	  your box. If you have PCI, say Y, otherwise N.
> +
> +
> +config PCI_DEBUG
> +	bool "PCI Debugging"
> +	depends on PCI
> +	help
> +	  Say Y here if you want the PCI core to produce a bunch of debug
> +	  messages to the system log.  Select this if you are having a
> +	  problem with PCI support and want to see more of what is going on.
> +
> +	  When in doubt, say N.
> +
> +endmenu
> +
> +endif
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> new file mode 100644
> index 0000000..c7d43c3
> --- /dev/null
> +++ b/drivers/pci/Makefile
> @@ -0,0 +1,8 @@
> +#
> +# Makefile for the PCI bus specific drivers.
> +#
> +obj-y		+= pci.o bus.o
> +
> +ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
> +
> +CPPFLAGS += $(ccflags-y)
> diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
> new file mode 100644
> index 0000000..8215ee5
> --- /dev/null
> +++ b/drivers/pci/bus.c
> @@ -0,0 +1,110 @@
> +#include <common.h>
> +#include <init.h>
> +#include <driver.h>
> +#include <linux/pci.h>
> +
> +/**
> + * pci_match_one_device - Tell if a PCI device structure has a matching
> + *                        PCI device id structure
> + * @id: single PCI device id structure to match
> + * @dev: the PCI device structure to match against
> + *
> + * Returns the matching pci_device_id structure or %NULL if there is no match.
> + */
> +static inline const struct pci_device_id *
> +pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev)
> +{
> +	if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) &&
> +	    (id->device == PCI_ANY_ID || id->device == dev->device) &&
> +	    (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) &&
> +	    (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) &&
> +	    !((id->class ^ dev->class) & id->class_mask))
> +		return id;
> +	return NULL;
> +}
> +
> +static int pci_match(struct device_d *dev, struct driver_d *drv)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct pci_driver *pdrv = to_pci_driver(drv);
> +	struct pci_device_id *id;
> +
> +	for (id = (struct pci_device_id *)pdrv->id_table; id->vendor; id++)
> +		if (pci_match_one_device(id, pdev)) {
> +			dev->priv = id;
> +			return 0;
> +		}
> +
> +	return -1;
> +}
> +
> +static int pci_probe(struct device_d *dev)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct pci_driver *pdrv = to_pci_driver(dev->driver);
> +
> +	return pdrv->probe(pdev, dev->priv);
> +}
> +
> +static void pci_remove(struct device_d *dev)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct pci_driver *pdrv = to_pci_driver(dev->driver);
> +
> +	pdrv->remove(pdev);
> +}
> +
> +struct bus_type pci_bus = {
> +	.name = "pci",
> +	.match = pci_match,
> +	.probe = pci_probe,
> +	.remove = pci_remove,
> +};
> +
> +static int pci_bus_init(void)
> +{
> +	return bus_register(&pci_bus);
> +}
> +pure_initcall(pci_bus_init);
> +
> +int pci_register_driver(struct pci_driver *pdrv)
> +{
> +	struct driver_d *drv = &pdrv->driver;
> +
> +	if (!pdrv->id_table)
> +		return -EIO;
> +
> +	drv->name = pdrv->name;
> +	drv->bus = &pci_bus;
> +
> +	return register_driver(drv);
> +}
> +
> +int pci_register_device(struct pci_dev *pdev)
> +{
> +	char str[6];
> +	struct device_d *dev = &pdev->dev;
> +	int ret;
> +
> +	strcpy(dev->name, "pci");
> +	dev->bus = &pci_bus;
> +	dev->id = DEVICE_ID_DYNAMIC;
> +
> +	ret = register_device(dev);
> +
> +	if (ret)
> +		return ret;
> +
> +	sprintf(str, "%02x", pdev->devfn);
> +	dev_add_param_fixed(dev, "devfn", str);
> +	sprintf(str, "%04x", (pdev->class >> 8) & 0xffff);
> +	dev_add_param_fixed(dev, "class", str);
> +	sprintf(str, "%04x", pdev->vendor);
> +	dev_add_param_fixed(dev, "vendor", str);
> +	sprintf(str, "%04x", pdev->device);
> +	dev_add_param_fixed(dev, "device", str);
> +	sprintf(str, "%04x", pdev->revision);
> +	dev_add_param_fixed(dev, "revision", str);
> +
> +	return 0;
> +}
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> new file mode 100644
> index 0000000..554cf64
> --- /dev/null
> +++ b/drivers/pci/pci.c
> @@ -0,0 +1,285 @@
> +#include <common.h>
> +#include <linux/pci.h>
> +
> +#ifdef DEBUG
> +#define DBG(x...) printk(x)
> +#else
> +#define DBG(x...)
> +#endif

Can we use the standard debug() macro instead please? Also a

#define pr_fmt(fmt) "PCI: " fmt

helps giving the PCI messages some context.


> +		default:				    /* unknown header */
> +		bad:
> +			printk(KERN_ERR "PCI: %02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
> +			       bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);

With the pr_fmt this could become:

			pr_err("%02x:%02x [%04x/%04x/%06x] has unknown header type %02x, ignoring.\n",
				bus->number, dev->devfn, dev->vendor, dev->device, class, hdr_type);

> +	struct list_head resources;	/* address space routed to this bus */
> +
> +	struct pci_ops	*ops;		/* configuration access functions */
> +	void		*sysdata;	/* hook for sys-specific extension */
> +	struct proc_dir_entry *procdir;	/* directory entry in /proc/bus/pci */

Doesn't this give a warning? We do no have struct proc_dir_entry

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC v4 4/6] net: add RealTek RTL-8139 PCI Ethernet driver
  2014-06-30 19:59 ` [RFC v4 4/6] net: add RealTek RTL-8139 PCI Ethernet driver Antony Pavlov
@ 2014-07-02  6:18   ` Sascha Hauer
  0 siblings, 0 replies; 10+ messages in thread
From: Sascha Hauer @ 2014-07-02  6:18 UTC (permalink / raw)
  To: Antony Pavlov; +Cc: barebox

On Mon, Jun 30, 2014 at 11:59:47PM +0400, Antony Pavlov wrote:
> This driver is based on Linux 2.6.39 8139too driver.
> 
> Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
> Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
> ---
>  drivers/net/Kconfig     |   8 +
>  drivers/net/Makefile    |   1 +
>  drivers/net/rtl8139.c   | 616 ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/pci_ids.h |   5 +
>  4 files changed, 630 insertions(+)
> 
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 7a0d5e1..975c927 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -130,6 +130,14 @@ config DRIVER_NET_ORION
>  	select PHYLIB
>  	select MDIO_MVEBU
>  
> +config DRIVER_NET_RTL8139
> +	bool "RealTek RTL-8139 PCI Ethernet driver"
> +	depends on PCI
> +	select PHYLIB
> +	help
> +	  This is a driver for the Fast Ethernet PCI network cards based on
> +	  the RTL 8139 chips.
> +
>  config DRIVER_NET_SMC911X
>  	bool "smc911x ethernet driver"
>  	select PHYLIB
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index 65f0d8b..d907061 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_DRIVER_NET_MICREL)		+= ksz8864rmn.o
>  obj-$(CONFIG_DRIVER_NET_MPC5200)	+= fec_mpc5200.o
>  obj-$(CONFIG_DRIVER_NET_NETX)		+= netx_eth.o
>  obj-$(CONFIG_DRIVER_NET_ORION)		+= orion-gbe.o
> +obj-$(CONFIG_DRIVER_NET_RTL8139)	+= rtl8139.o
>  obj-$(CONFIG_DRIVER_NET_SMC911X)	+= smc911x.o
>  obj-$(CONFIG_DRIVER_NET_SMC91111)	+= smc91111.o
>  obj-$(CONFIG_DRIVER_NET_TAP)		+= tap.o
> diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
> new file mode 100644
> index 0000000..82c3585
> --- /dev/null
> +++ b/drivers/net/rtl8139.c
> @@ -0,0 +1,616 @@
> +#include <common.h>
> +#include <net.h>
> +#include <malloc.h>
> +#include <init.h>
> +#include <xfuncs.h>
> +#include <errno.h>
> +#include <io.h>
> +#include <linux/phy.h>
> +#include <linux/pci.h>
> +
> +#include <asm/dma-mapping.h>
> +
> +#define RTL8139_DEBUG
> +#undef RTL8139_DEBUG
> +
> +/*
> + * Receive ring size
> + * Warning: 64K ring has hardware issues and may lock up.
> + */
> +#define RX_BUF_IDX	0	/* 8K ring */
> +#define RX_BUF_LEN	(8192 << RX_BUF_IDX)
> +#define RX_BUF_PAD	16
> +#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
> +
> +#if RX_BUF_LEN == 65536
> +#define RX_BUF_TOT_LEN	RX_BUF_LEN
> +#else
> +#define RX_BUF_TOT_LEN	(RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
> +#endif
> +
> +/* Number of Tx descriptor registers. */
> +#define NUM_TX_DESC	4
> +
> +/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
> +#define MAX_ETH_FRAME_SIZE	1536
> +
> +/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
> +#define TX_BUF_SIZE	MAX_ETH_FRAME_SIZE
> +#define TX_BUF_TOT_LEN	(TX_BUF_SIZE * NUM_TX_DESC)
> +
> +/* PCI Tuning Parameters
> +   Threshold is bytes transferred to chip before transmission starts. */
> +#define TX_FIFO_THRESH 256	/* In bytes, rounded down to 32 byte units. */
> +
> +/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
> +#define RX_FIFO_THRESH	7	/* Rx buffer level before first PCI xfer.  */
> +#define RX_DMA_BURST	7	/* Maximum PCI burst, '6' is 1024 */
> +#define TX_DMA_BURST	6	/* Maximum PCI burst, '6' is 1024 */
> +#define TX_RETRY	8	/* 0-15.  retries = 16 + (TX_RETRY * 16) */
> +
> +struct rtl8139_priv {
> +	struct eth_device	edev;
> +	void __iomem		*base;
> +	struct pci_dev		*pci_dev;
> +	unsigned char		*rx_ring;
> +	unsigned int		cur_rx; /* RX buf index of next pkt */
> +	dma_addr_t		rx_ring_dma;
> +
> +	u32			rx_config;
> +	unsigned int		tx_flag;
> +	unsigned long		cur_tx;
> +	unsigned long		dirty_tx;
> +	unsigned char		*tx_buf[NUM_TX_DESC];   /* Tx bounce buffers */
> +	unsigned char		*tx_bufs;       /* Tx bounce buffer region. */
> +	dma_addr_t		tx_bufs_dma;
> +
> +	struct mii_bus miibus;
> +};
> +
> +#define ETH_ZLEN        60              /* Min. octets in frame sans FCS */
> +
> +/* Registers */
> +#define MAC0		0x00
> +#define MAR0		0x08
> +#define TxStatus0	0x10
> +
> +enum TxStatusBits {
> +	TxHostOwns	= 0x2000,
> +	TxUnderrun	= 0x4000,
> +	TxStatOK	= 0x8000,
> +	TxOutOfWindow	= 0x20000000,
> +	TxAborted	= 0x40000000,
> +	TxCarrierLost	= 0x80000000,
> +};
> +
> +#define TxAddr0		0x20
> +#define RxBuf		0x30
> +#define ChipCmd		0x37
> +#define  CmdReset	0x10
> +#define  CmdRxEnb	0x08
> +#define  CmdTxEnb	0x04
> +#define  RxBufEmpty	0x01
> +#define RxBufPtr	0x38
> +#define RxBufAddr	0x3A
> +#define IntrMask	0x3C
> +#define IntrStatus	0x3E
> +#define  PCIErr		0x8000
> +#define  PCSTimeout	0x4000
> +#define  RxFIFOOver	0x0040
> +#define  RxUnderrun	0x0020
> +#define  RxOverflow	0x0010
> +#define  TxErr		0x0008
> +#define  TxOK		0x0004
> +#define  RxErr		0x0002
> +#define  RxOK		0x0001
> +#define    RxAckBits	(RxFIFOOver | RxOverflow | RxOK)
> +
> +#define TxConfig	0x40
> +/* Bits in TxConfig. */
> +enum tx_config_bits {
> +	/* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
> +	TxIFGShift	= 24,
> +	TxIFG84		= (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
> +	TxIFG88		= (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
> +	TxIFG92		= (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
> +	TxIFG96		= (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
> +
> +	TxLoopBack	= (1 << 18) | (1 << 17), /* enable loopback test mode */
> +	TxCRC		= (1 << 16),	/* DISABLE Tx pkt CRC append */
> +	TxClearAbt	= (1 << 0),	/* Clear abort (WO) */
> +	TxDMAShift	= 8, /* DMA burst value (0-7) is shifted X many bits */
> +	TxRetryShift	= 4, /* TXRR value (0-15) is shifted X many bits */
> +
> +	TxVersionMask	= 0x7C800000, /* mask out version bits 30-26, 23 */
> +};
> +
> +#define RxConfig	0x44
> +	/* rx fifo threshold */
> +#define  RxCfgFIFOShift	13
> +#define	 RxCfgFIFONone	(7 << RxCfgFIFOShift)
> +	/* Max DMA burst */
> +#define	 RxCfgDMAShift	8
> +#define	 RxCfgDMAUnlimited (7 << RxCfgDMAShift)
> +	/* rx ring buffer length */
> +#define	 RxCfgRcv8K	0
> +#define	 RxCfgRcv16K	(1 << 11)
> +#define	 RxCfgRcv32K	(1 << 12)
> +#define	 RxCfgRcv64K	((1 << 11) | (1 << 12))
> +	/* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
> +#define	 RxNoWrap	(1 << 7)
> +#define	 AcceptErr		0x20
> +#define	 AcceptRunt		0x10
> +#define	 AcceptBroadcast	0x08
> +#define	 AcceptMulticast	0x04
> +#define	 AcceptMyPhys		0x02
> +#define	 AcceptAllPhys		0x01
> +
> +#define RxMissed	0x4C
> +#define Cfg9346		0x50
> +#define  Cfg9346_Lock	0x00
> +#define  Cfg9346_Unlock	0xC0
> +#define BasicModeCtrl	0x62
> +#define BasicModeStatus	0x64
> +#define NWayAdvert	0x66
> +#define NWayLPAR	0x68
> +#define NWayExpansion	0x6a
> +
> +static const char mii_2_8139_map[8] = {
> +	BasicModeCtrl,
> +	BasicModeStatus,
> +	0,
> +	0,
> +	NWayAdvert,
> +	NWayLPAR,
> +	NWayExpansion,
> +	0
> +};
> +
> +/* write MMIO register */
> +#define RTL_W8(priv, reg, val)	writeb(val, ((char *)(priv->base) + reg))
> +#define RTL_W16(priv, reg, val)	writew(val, ((char *)(priv->base) + reg))
> +#define RTL_W32(priv, reg, val)	writel(val, ((char *)(priv->base) + reg))
> +
> +/* read MMIO register */
> +#define RTL_R8(priv, reg)	readb(((char *)(priv->base) + reg))
> +#define RTL_R16(priv, reg)	readw(((char *)(priv->base) + reg))
> +#define RTL_R32(priv, reg)	readl(((char *)(priv->base) + reg))
> +
> +/* write MMIO register, with flush */
> +/* Flush avoids rtl8139 bug w/ posted MMIO writes */
> +static inline void RTL_W8_F(struct rtl8139_priv *priv, int reg, int val)
> +{
> +	RTL_W8(priv, reg, val);
> +	RTL_R8(priv, reg);
> +}
> +
> +static inline void RTL_W16_F(struct rtl8139_priv *priv, int reg, int val)
> +{
> +	RTL_W16(priv, reg, val);
> +	RTL_R16(priv, reg);
> +}
> +
> +static inline void RTL_W32_F(struct rtl8139_priv *priv, int reg, int val)
> +{
> +	RTL_W32(priv, reg, val);
> +	RTL_R32(priv, reg);
> +}
> +
> +static const unsigned int rtl8139_rx_config =
> +	RxCfgRcv8K | RxNoWrap |
> +	(RX_FIFO_THRESH << RxCfgFIFOShift) |
> +	(RX_DMA_BURST << RxCfgDMAShift);
> +
> +static const unsigned int rtl8139_tx_config =
> +	TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
> +
> +static void rtl8139_chip_reset(struct rtl8139_priv *priv)
> +{
> +	int i;
> +
> +	/* Soft reset the chip. */
> +	RTL_W8(priv, ChipCmd, CmdReset);
> +
> +	/* Check that the chip has finished the reset. */
> +	for (i = 1000; i > 0; i--) {
> +		if ((RTL_R8(priv, ChipCmd) & CmdReset) == 0)
> +			break;
> +		udelay(10);
> +	}
> +}
> +
> +static void __set_rx_mode(struct rtl8139_priv *priv)
> +{
> +	u32 mc_filter[2];	/* Multicast hash filter */
> +	int rx_mode;
> +	u32 tmp;
> +
> +	rx_mode =
> +	    AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
> +	    AcceptAllPhys;
> +	mc_filter[1] = mc_filter[0] = 0xffffffff;
> +
> +	/* We can safely update without stopping the chip. */
> +	tmp = rtl8139_rx_config | rx_mode;
> +	if (priv->rx_config != tmp) {
> +		RTL_W32_F(priv, RxConfig, tmp);
> +		priv->rx_config = tmp;
> +	}
> +
> +	RTL_W32_F(priv, MAR0 + 0, mc_filter[0]);
> +	RTL_W32_F(priv, MAR0 + 4, mc_filter[1]);
> +}
> +
> +/* Start the hardware at open or resume. */
> +static void rtl8139_hw_start(struct rtl8139_priv *priv)
> +{
> +	u32 i;
> +	u8 tmp;
> +
> +	rtl8139_chip_reset(priv);
> +
> +	/* unlock Config[01234] and BMCR register writes */
> +	RTL_W8_F(priv, Cfg9346, Cfg9346_Unlock);
> +
> +	/* FIXME */
> +#if 0
> +	/* Restore our idea of the MAC address. */
> +	RTL_W32_F(priv, MAC0 + 0, *(__le32 *) (dev->dev_addr + 0));
> +	RTL_W32_F(priv, MAC0 + 4, *(__le16 *) (dev->dev_addr + 4));
> +#endif

Is this something that needs fixing? The MAC Address should be
configured correctly without this code, right?

> +	priv->miibus.read = rtl8139_phy_read;
> +	priv->miibus.write = rtl8139_phy_write;
> +	priv->miibus.priv = priv;
> +	priv->miibus.parent = &edev->dev;
> +
> +	/* FIXME: pci_resource_start() */
> +	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &bar);
> +
> +	/* FIXME: use pci_iomap() */
> +	priv->base = (void *)bus->ops->res_start(bus, bar);

barebox has resources. Can't we use them here? What's missing?

> +
> +	printk("found rtl8139 (rev %02x) at %02x: %04x (base=%p)\n",
> +			pdev->revision,
> +			pdev->devfn,
> +			(pdev->class >> 8) & 0xffff,
> +			priv->base);

dev_info

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-07-02  6:18 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-30 19:59 [RFC v4 0/6] barebox PCI support Antony Pavlov
2014-06-30 19:59 ` [RFC v4 1/6] MIPS: add dma_alloc_coherent() Antony Pavlov
2014-06-30 19:59 ` [RFC v4 2/6] PCI: initial commit Antony Pavlov
2014-07-02  6:12   ` Sascha Hauer
2014-06-30 19:59 ` [RFC v4 3/6] commands: add 'lspci' command Antony Pavlov
2014-06-30 19:59 ` [RFC v4 4/6] net: add RealTek RTL-8139 PCI Ethernet driver Antony Pavlov
2014-07-02  6:18   ` Sascha Hauer
2014-06-30 19:59 ` [RFC v4 5/6] MIPS: add PCI support for GT64120-based Malta board Antony Pavlov
2014-06-30 19:59 ` [RFC v4 6/6] MIPS: qemu-malta_defconfig: enable PCI & network stuff Antony Pavlov
2014-07-02  6:05 ` [RFC v4 0/6] barebox PCI support Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox