x86: minnowmax: Move USB and Ethernet to driver model
Subsystems (7)
cover x86: minnowmax: Move USB and Ethernet to driver model
This series aims to move minnowmax (an x86 board) to use driver model for USB and Ethernet.
Since there is some support lacking, it includes:
- driver-model conversion of asix USB Ethernet driver
- driver-model conversion of Realtek 8169 Ethernet driver
- PCI device matching without using device tree
- driver-model conversion of USB Ethernet layer
- driver-model conversion of ehci_pci driver
Also it includes a proposed change to the Ethernet uclass recv method to support slow devices better.
Simon Glass (18):
dm: core: Add \n to two dm_warn() messages
usb: ehci: Correct a missing hypen in an error message
usb: Update some EHCI driver licenses to use SPDX
x86: Show the un-relocated IP address in exceptions
dm: pci: Add support for PCI driver matching
dm: eth: Add driver-model support to the rtl8169 driver
dm: pci: Add a function to get the BDF for a device
dm: usb: Correct the struct usb_driver_entry comment
dm: usb: Avoid using USB ethernet with CONFIG_DM_USB and no DM_ETH
dm: eth: Avoid blocking on packet reception
dm: usb: eth: Support driver model with USB Ethernet
dm: usb: Adjust the USB_DEVICE() macro naming
x86: minnowmax: Drop the cache line size hack
dm: usb: Add driver-model support to ehci-pci
dm: usb: eth: Add driver-model support to the asix driver
net: Allow drivers to return -ENOSYS with the write_hwaddr() method
x86: Convert minnowmax to use CONFIG_DM_NET
x86: Convert minnowmax to use CONFIG_DM_USB
arch/x86/cpu/interrupts.c | 2 + board/intel/minnowmax/minnowmax.c | 6 - common/cmd_usb.c | 14 ++- common/usb_hub.c | 2 +- common/usb_kbd.c | 4 +- common/usb_storage.c | 2 +- configs/minnowmax_defconfig | 3 + drivers/core/device.c | 4 +- drivers/net/designware.c | 2 +- drivers/net/rtl8169.c | 236 +++++++++++++++++++++++++++++-------- drivers/net/sandbox-raw.c | 2 +- drivers/net/sandbox.c | 2 +- drivers/net/sunxi_emac.c | 2 +- drivers/pci/pci-uclass.c | 144 ++++++++++++++++++++--- drivers/pci/pci_compat.c | 8 +- drivers/usb/Kconfig | 4 +- drivers/usb/eth/asix.c | 237 ++++++++++++++++++++++++++++++++++---- drivers/usb/eth/usb_ether.c | 131 ++++++++++++++++++++- drivers/usb/host/ehci-hcd.c | 17 +-- drivers/usb/host/ehci-pci.c | 112 ++++++++++++------ drivers/usb/host/ehci.h | 15 +-- drivers/usb/host/r8a66597-hcd.c | 14 +-- drivers/usb/host/r8a66597.h | 14 +-- include/configs/minnowmax.h | 3 - include/net.h | 14 ++- include/pci.h | 87 +++++++++++++- include/usb.h | 22 +++- include/usb_ether.h | 89 ++++++++++++-- net/eth.c | 11 +- 29 files changed, 971 insertions(+), 232 deletions(-)
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 1/18 dm: core: Add \n to two dm_warn() messages
These should finish with a newline like the others.
---
drivers/core/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/core/device.c +2 -2
@@ -330,7 +330,7 @@ void *dev_get_platdata(struct udevice *dev)void *dev_get_parent_platdata (struct udevice *dev) {if (!dev) { -dm_warn ("%s: null device" , __func__); +dm_warn ("%s: null device\n" , __func__);return NULL ; }
@@ -340,7 +340,7 @@ void *dev_get_parent_platdata(struct udevice *dev)void *dev_get_uclass_platdata (struct udevice *dev) {if (!dev) { -dm_warn ("%s: null device" , __func__); +dm_warn ("%s: null device\n" , __func__);return NULL ; }
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 1/18 dm: core: Add \n to two dm_warn() messages
Quoted 8 lines · Simon Glass
These should finish with a newline like the others.
Signed-off-by Simon Glass <[email protected]>---
drivers/core/device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Applied to u-boot-dm.
PATCH 2/18 usb: ehci: Correct a missing hypen in an error message
In reply to Simon GlassAdd a hyphen to correct the grammar.
---
drivers/usb/host/ehci-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/host/ehci-hcd.c +1 -1
@@ -321,7 +321,7 @@ static void ehci_update_endpt2_dev_n_port(struct usb_device *udev,struct udevice *dev = parent;if (device_get_uclass_id (dev->parent) !=UCLASS_USB_HUB ) { -printf ("ehci: Error cannot find high speed parent of usb-1 device\n" ); +printf ("ehci: Error cannot find high-speed parent of usb-1 device\n" );return ; }
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 2/18 usb: ehci: Correct a missing hypen in an error message
Quoted 3 lines · Simon Glass
Add a hyphen to correct the grammar.
Signed-off-by Simon Glass <[email protected]>
Acked by: Marek Vasut <[email protected]>
Best regards,
Marek Vasut
PATCH 2/18 usb: ehci: Correct a missing hypen in an error message
Quoted 9 lines · Marek Vasut
Quoted 3 lines · Simon Glass
Add a hyphen to correct the grammar.
Signed-off-by Simon Glass <[email protected]>Acked by: Marek Vasut <[email protected]>
Best regards,
Marek Vasut
Applied to u-boot-dm.
PATCH 3/18 usb: Update some EHCI driver licenses to use SPDX
In reply to Simon GlassA few drivers still write out the license in full. Fix these.
---
drivers/usb/host/ehci-hcd.c | 15 +-------------- drivers/usb/host/ehci-pci.c | 15 +-------------- drivers/usb/host/ehci.h | 15 +-------------- drivers/usb/host/r8a66597-hcd.c | 14 +------------- drivers/usb/host/r8a66597.h | 14 +------------- 5 files changed, 5 insertions(+), 68 deletions(-)
drivers/usb/host/ehci-hcd.c +1 -14
@@ -5,20 +5,7 @@* * All rights reserved. * -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation version 2 of -* the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, -* MA 02111-1307 USA +* SPDX-License-Identifier: GPL-2.0 */ #include <common.h> #include <dm.h>
drivers/usb/host/ehci-pci.c +1 -14
@@ -2,20 +2,7 @@* Copyright (c) 2007-2008, Juniper Networks, Inc. * All rights reserved. * -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation version 2 of -* the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, -* MA 02111-1307 USA +* SPDX-License-Identifier: GPL-2.0 */ #include <common.h>
drivers/usb/host/ehci.h +1 -14
@@ -3,20 +3,7 @@* Copyright (c) 2008, Michael Trimarchi <[email protected]> * All rights reserved. * -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation version 2 of -* the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, -* MA 02111-1307 USA +* SPDX-License-Identifier: GPL-2.0 */ #ifndef USB_EHCI_H
drivers/usb/host/r8a66597-hcd.c +1 -13
@@ -3,19 +3,7 @@* * Copyright (C) 2008 Yoshihiro Shimoda <[email protected]> * -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; version 2 of the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -* +* SPDX-License-Identifier: GPL-2.0 */ #include <common.h>
drivers/usb/host/r8a66597.h +1 -13
@@ -3,19 +3,7 @@* * Copyright (C) 2008 Yoshihiro Shimoda <[email protected]> * -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; version 2 of the License. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -* +* SPDX-License-Identifier: GPL-2.0 */ #ifndef __R8A66597_H__
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 3/18 usb: Update some EHCI driver licenses to use SPDX
Quoted 3 lines · Simon Glass
A few drivers still write out the license in full. Fix these.
Signed-off-by Simon Glass <[email protected]>
Thanks!
Best regards,
Marek Vasut
PATCH 3/18 usb: Update some EHCI driver licenses to use SPDX
Quoted 11 lines · Marek Vasut
Quoted 3 lines · Simon Glass
A few drivers still write out the license in full. Fix these.
Signed-off-by Simon Glass <[email protected]>Thanks!
Acked-by Marek Vasut <[email protected]>Best regards,
Marek Vasut
Applied to u-boot-dm.
PATCH 4/18 x86: Show the un-relocated IP address in exceptions
In reply to Simon GlassWhen trying to figure out where an exception has occured, the relocated address is not a lot of help. Its value depends on various factors. Show the un-relocated IP as well. This can be looked up in System.map directly.
---
arch/x86/cpu/interrupts.c | 2 ++ 1 file changed, 2 insertions(+)
arch/x86/cpu/interrupts.c +2 -0
@@ -40,6 +40,8 @@ static void dump_regs(struct irq_regs *regs)printf ("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n" , (u16 )regs->xcs, regs->eip, regs->eflags); +if (gd->flags &GD_FLG_RELOC ) +printf ("reloc EIP : [<%08lx>]\n" , regs->eip - gd->reloc_off);printf ("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n" , regs->eax, regs->ebx, regs->ecx, regs->edx);
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 4/18 x86: Show the un-relocated IP address in exceptions
Hi Simon,
Quoted 7 lines · Simon Glass
When trying to figure out where an exception has occured, the relocated address is not a lot of help. Its value depends on various factors. Show the un-relocated IP as well. This can be looked up in System.map directly.
Signed-off-by Simon Glass <[email protected]>---
Some nits below:
arch/x86/cpu/interrupts.c static void dump_regs(struct irq_regs *regs) · line 44
Quoted 13 lines
arch/x86/cpu/interrupts.c | 2 ++ 1 file changed, 2 insertions(+)arch/x86/cpu/interrupts.c +2
-0@@ -40,6 +40,8 @@ static void dump_regs(struct irq_regs *regs)printf ("EIP: %04x:[<%08lx>] EFLAGS: %08lx\n" , (u16 )regs->xcs, regs->eip, regs->eflags); +if (gd->flags &GD_FLG_RELOC ) +printf ("reloc EIP : [<%08lx>]\n" , regs->eip - gd->reloc_off);
Could it be 'Original EIP' instead of 'reloc EIP'? To me, 'reloc EIP' sounds confusing. And the space followed immediately after ':' can be removed?
arch/x86/cpu/interrupts.c static void dump_regs(struct irq_regs *regs)
Quoted 4 lines
arch/x86/cpu/interrupts.c +0
-1printf ("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n" , regs->eax, regs->ebx, regs->ecx, regs->edx); --
Regards,
Bin
PATCH 5/18 dm: pci: Add support for PCI driver matching
In reply to Simon GlassAt present all PCI devices must be present in the device tree in order to be used. Many or most PCI devices don't require any configuration other than that which is done automatically by U-Boot. It is inefficent to add a node with nothing but a compatible string in order to get a device working.
Add a mechanism whereby PCI drivers can be declared along with the device parameters they support (vendor/device/class). When no suitable driver is found in the device tree the list of such devices is consulted to determine the correct driver. If this also fails, then a generic driver is used as before.
The mechanism used is very similar to that provided by Linux and the header file defintions are copied from Linux 4.1.
---
drivers/pci/pci-uclass.c | 129 ++++++++++++++++++++++++++++++++++++++++++----- include/pci.h | 79 ++++++++++++++++++++++++++++- 2 files changed, 193 insertions(+), 15 deletions(-)
drivers/pci/pci-uclass.c +116 -13
@@ -353,6 +353,101 @@ int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf)return sub_bus; } +/** +* 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 bool pci_match_one_id (const struct pci_device_id *id, +const struct pci_device_id *find) +{ +if ((id->vendor ==PCI_ANY_ID || id->vendor == find->vendor) && + (id->device ==PCI_ANY_ID || id->device == find->device) && + (id->subvendor ==PCI_ANY_ID || id->subvendor == find->subvendor) && + (id->subdevice ==PCI_ANY_ID || id->subdevice == find->subdevice) && + !((id->class ^ find->class) & id->class_mask)) +return true; + +return false; +} + +/** +* pci_find_and_bind_driver() - Find and bind the right PCI driver +* +* This only looks at certain fields in the descriptor. +*/ +static int pci_find_and_bind_driver (struct udevice *parent, +struct pci_device_id *find_id,int devfn, +struct udevice **devp) +{ +struct pci_driver_entry *start, *entry; +const char *drv; +int n_ents; +int ret; +char name[30 ], *str; + + *devp =NULL ; + +debug ("%s: Searching for driver: vendor=%x, device=%x\n" , __func__, + find_id->vendor, find_id->device); + start = ll_entry_start(struct pci_driver_entry, pci_driver_entry); + n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry); +for (entry = start; entry != start + n_ents; entry++) { +const struct pci_device_id *id; +struct udevice *dev; +const struct driver *drv; + +for (id = entry->match; + id->vendor || id->subvendor || id->class_mask; + id++) { +if (!pci_match_one_id (id, find_id)) +continue ; + + drv = entry->driver; +/* +* We could pass the descriptor to the driver as +* platdata (instead of NULL) and allow its bind() +* method to return -ENOENT if it doesn't support this +* device. That way we could continue the search to +* find another driver. For now this doesn't seem +* necesssary, so just bind the first match. +*/ + ret =device_bind (parent, drv, drv->name,NULL ,-1 , + &dev); +if (ret) + goto error; +debug ("%s: Match found: %s\n" , __func__, drv->name); + dev->driver_data = find_id->driver_data; + *devp = dev; +return 0 ; + } + } + +/* Bind a generic driver so that the device can be used */ +sprintf (name,"pci_%x:%x.%x" , parent->seq,PCI_DEV (devfn), +PCI_FUNC (devfn)); + str =strdup (name); +if (!str) +return -ENOMEM ; + drv = (find_id->class >>8 ) ==PCI_CLASS_BRIDGE_PCI ?"pci_bridge_drv" : +"pci_generic_drv" ; + ret =device_bind_driver (parent, drv, str, devp); +if (ret) { +debug ("%s: Failed to bind generic driver: %d" , __func__, ret); +return ret; + } +debug ("%s: No match found: bound generic driver instead\n" , __func__); + +return 0 ; + +error: +debug ("%s: No match found: error %d\n" , __func__, ret); +return ret; +} +int pci_bind_bus_devices (struct udevice *bus) {ulong vendor, device;
@@ -387,25 +482,33 @@ int pci_bind_bus_devices(struct udevice *bus) bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));pci_bus_read_config (bus, devfn,PCI_DEVICE_ID , &device,PCI_SIZE_16 ); -pci_bus_read_config (bus, devfn,PCI_CLASS_DEVICE , &class, -PCI_SIZE_16 ); +pci_bus_read_config (bus, devfn,PCI_CLASS_REVISION , &class, +PCI_SIZE_32 ); + class >>=8 ;/* Find this device in the device tree */ ret =pci_bus_find_devfn (bus, devfn, &dev); +/* Search for a driver */ +/* If nothing in the device tree, bind a generic device */ if (ret == -ENODEV ) { -char name[30 ], *str; -const char *drv; - -sprintf (name,"pci_%x:%x.%x" , bus->seq, -PCI_DEV (devfn),PCI_FUNC (devfn)); - str =strdup (name); -if (!str) -return -ENOMEM ; - drv = class ==PCI_CLASS_BRIDGE_PCI ? -"pci_bridge_drv" :"pci_generic_drv" ; - ret =device_bind_driver (bus, drv, str, &dev); +struct pci_device_id find_id; +ulong val; + +memset (&find_id,'\0' ,sizeof (find_id)); + find_id.vendor = vendor; + find_id.device = device; + find_id.class = class; +if ((header_type &0x7f ) ==PCI_HEADER_TYPE_NORMAL ) { +pci_bus_read_config (bus, devfn, +PCI_SUBSYSTEM_VENDOR_ID , + &val,PCI_SIZE_32 ); + find_id.subvendor = val &0xffff ; + find_id.subdevice = val >>16 ; + } + ret =pci_find_and_bind_driver (bus, &find_id, devfn, + &dev); }if (ret)return ret;
include/pci.h +77 -2
91 lines not on this page · raw message
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 5/18 dm: pci: Add support for PCI driver matching
Hi Simon,
Quoted 11 lines · Simon Glass
At present all PCI devices must be present in the device tree in order to be used. Many or most PCI devices don't require any configuration other than that which is done automatically by U-Boot. It is inefficent to add a node with nothing but a compatible string in order to get a device working.
Add a mechanism whereby PCI drivers can be declared along with the device parameters they support (vendor/device/class). When no suitable driver is found in the device tree the list of such devices is consulted to determine the correct driver. If this also fails, then a generic driver is used as before.
Quoted 5 lines
The mechanism used is very similar to that provided by Linux and the header file defintions are copied from Linux 4.1.
Signed-off-by Simon Glass <[email protected]>---
PATCH 5/18 dm: pci: Add support for PCI driver matching
In reply to Simon GlassHi Simon,
Quoted 179 lines · Simon Glass
At present all PCI devices must be present in the device tree in order to be used. Many or most PCI devices don't require any configuration other than that which is done automatically by U-Boot. It is inefficent to add a node with nothing but a compatible string in order to get a device working.
Add a mechanism whereby PCI drivers can be declared along with the device parameters they support (vendor/device/class). When no suitable driver is found in the device tree the list of such devices is consulted to determine the correct driver. If this also fails, then a generic driver is used as before.
The mechanism used is very similar to that provided by Linux and the header file defintions are copied from Linux 4.1.
Signed-off-by Simon Glass <[email protected]>---
drivers/pci/pci-uclass.c | 129 ++++++++++++++++++++++++++++++++++++++++++----- include/pci.h | 79 ++++++++++++++++++++++++++++- 2 files changed, 193 insertions(+), 15 deletions(-)drivers/pci/pci-uclass.c +116
-13@@ -353,6 +353,101 @@ int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf)return sub_bus; } +/** +* 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 bool pci_match_one_id (const struct pci_device_id *id, +const struct pci_device_id *find) +{ +if ((id->vendor ==PCI_ANY_ID || id->vendor == find->vendor) && + (id->device ==PCI_ANY_ID || id->device == find->device) && + (id->subvendor ==PCI_ANY_ID || id->subvendor == find->subvendor) && + (id->subdevice ==PCI_ANY_ID || id->subdevice == find->subdevice) && + !((id->class ^ find->class) & id->class_mask)) +return true; + +return false; +} + +/** +* pci_find_and_bind_driver() - Find and bind the right PCI driver +* +* This only looks at certain fields in the descriptor. +*/ +static int pci_find_and_bind_driver (struct udevice *parent, +struct pci_device_id *find_id,int devfn, +struct udevice **devp) +{ +struct pci_driver_entry *start, *entry; +const char *drv; +int n_ents; +int ret; +char name[30 ], *str; + + *devp =NULL ; + +debug ("%s: Searching for driver: vendor=%x, device=%x\n" , __func__, + find_id->vendor, find_id->device); + start = ll_entry_start(struct pci_driver_entry, pci_driver_entry); + n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry); +for (entry = start; entry != start + n_ents; entry++) { +const struct pci_device_id *id; +struct udevice *dev; +const struct driver *drv; + +for (id = entry->match; + id->vendor || id->subvendor || id->class_mask; + id++) { +if (!pci_match_one_id (id, find_id)) +continue ; + + drv = entry->driver; +/* +* We could pass the descriptor to the driver as +* platdata (instead of NULL) and allow its bind() +* method to return -ENOENT if it doesn't support this +* device. That way we could continue the search to +* find another driver. For now this doesn't seem +* necesssary, so just bind the first match. +*/ + ret =device_bind (parent, drv, drv->name,NULL ,-1 , + &dev); +if (ret) + goto error; +debug ("%s: Match found: %s\n" , __func__, drv->name); + dev->driver_data = find_id->driver_data; + *devp = dev; +return 0 ; + } + } + +/* Bind a generic driver so that the device can be used */ +sprintf (name,"pci_%x:%x.%x" , parent->seq,PCI_DEV (devfn), +PCI_FUNC (devfn)); + str =strdup (name); +if (!str) +return -ENOMEM ; + drv = (find_id->class >>8 ) ==PCI_CLASS_BRIDGE_PCI ?"pci_bridge_drv" : +"pci_generic_drv" ; + ret =device_bind_driver (parent, drv, str, devp); +if (ret) { +debug ("%s: Failed to bind generic driver: %d" , __func__, ret); +return ret; + } +debug ("%s: No match found: bound generic driver instead\n" , __func__); + +return 0 ; + +error: +debug ("%s: No match found: error %d\n" , __func__, ret); +return ret; +} +int pci_bind_bus_devices (struct udevice *bus) {ulong vendor, device;@@ -387,25 +482,33 @@ int pci_bind_bus_devices(struct udevice *bus) bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));pci_bus_read_config (bus, devfn,PCI_DEVICE_ID , &device,PCI_SIZE_16 ); -pci_bus_read_config (bus, devfn,PCI_CLASS_DEVICE , &class, -PCI_SIZE_16 ); +pci_bus_read_config (bus, devfn,PCI_CLASS_REVISION , &class, +PCI_SIZE_32 ); + class >>=8 ;/* Find this device in the device tree */ ret =pci_bus_find_devfn (bus, devfn, &dev); +/* Search for a driver */ +/* If nothing in the device tree, bind a generic device */ if (ret == -ENODEV ) { -char name[30 ], *str; -const char *drv; - -sprintf (name,"pci_%x:%x.%x" , bus->seq, -PCI_DEV (devfn),PCI_FUNC (devfn)); - str =strdup (name); -if (!str) -return -ENOMEM ; - drv = class ==PCI_CLASS_BRIDGE_PCI ? -"pci_bridge_drv" :"pci_generic_drv" ; - ret =device_bind_driver (bus, drv, str, &dev); +struct pci_device_id find_id; +ulong val; + +memset (&find_id,'\0' ,sizeof (find_id)); + find_id.vendor = vendor; + find_id.device = device; + find_id.class = class; +if ((header_type &0x7f ) ==PCI_HEADER_TYPE_NORMAL ) { +pci_bus_read_config (bus, devfn, +PCI_SUBSYSTEM_VENDOR_ID , + &val,PCI_SIZE_32 ); + find_id.subvendor = val &0xffff ; + find_id.subdevice = val >>16 ; + } + ret =pci_find_and_bind_driver (bus, &find_id, devfn, + &dev); }if (ret)return ret;include/pci.h +0
-0
include/pci.h typedef int pci_dev_t; · line 475
Quoted 9 lines
include/pci.h +4
-1@@ -468,7 +468,10 @@ typedef int pci_dev_t;#define PCI_ANY_ID (~0)struct pci_device_id { -unsigned int vendor, device;/* Vendor and device ID or PCI_ANY_ID */ +unsigned int vendor, device;/* Vendor and device ID or PCI_ANY_ID */ +unsigned int subvendor, subdevice;/* Subsystem ID's or PCI_ANY_ID */ +unsigned int class, class_mask;/* (class,subclass,prog-if) triplet */ +unsigned long driver_data;/* Data private to the driver */ };
Can we create another structure for dm? There are lots of codes which only defines vendor id and device id like below:
static struct pci_device_id mmc_supported[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_0 }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_1 },
};
Although compiler does not generate any error or warning, it is confusing.
Quoted 74 lines
include/pci.h +67
-1struct pci_controller ;@@ -1110,7 +1113,79 @@ struct dm_pci_emul_ops {int sandbox_pci_get_emul (struct udevice *bus,pci_dev_t find_devfn,struct udevice **emulp); -#endif +/** +* 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_SUB - macro used to describe a specific pci device with subsystem +* @vend: the 16 bit PCI Vendor ID +* @dev: the 16 bit PCI Device ID +* @subvend: the 16 bit PCI Subvendor ID +* @subdev: the 16 bit PCI Subdevice ID +* +* This macro is used to create a struct pci_device_id that matches a +* specific device with subsystem information. +*/ +#define PCI_DEVICE_SUB (vend, dev, subvend, subdev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = (subvend), .subdevice = (subdev) + +/** +* 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 + +/** +* struct pci_driver_entry - Matches a driver to its pci_device_id list +* @driver: Driver to use +* @match: List of match records for this driver, terminated by {} +*/ +struct pci_driver_entry { +struct driver *driver; +const struct pci_device_id *match; +}; + +#define U_BOOT_PCI_DEVICE (__name, __match) \
include/pci.h struct dm_pci_emul_ops {
Quoted 10 lines
include/pci.h +6
-1+ ll_entry_declare(struct pci_driver_entry, __name, pci_driver_entry) = {\ + .driver = llsym(struct driver, __name, driver), \ + .match = __match, \ + } + +#endif /* CONFIG_DM_PCI */ #endif /* __ASSEMBLY__ */ #endif /* _PCI_H */ --
Do you have plan to address the issue that dm pci cannot be used in the pre-reloc phase? Like we need pci uart as the U-Boot console.
Regards,
Bin
PATCH 5/18 dm: pci: Add support for PCI driver matching
Hi Bin,
Quoted 195 lines · Bin Meng
Hi Simon,
Quoted 179 lines · Simon Glass
At present all PCI devices must be present in the device tree in order to be used. Many or most PCI devices don't require any configuration other than that which is done automatically by U-Boot. It is inefficent to add a node with nothing but a compatible string in order to get a device working.
Add a mechanism whereby PCI drivers can be declared along with the device parameters they support (vendor/device/class). When no suitable driver is found in the device tree the list of such devices is consulted to determine the correct driver. If this also fails, then a generic driver is used as before.
The mechanism used is very similar to that provided by Linux and the header file defintions are copied from Linux 4.1.
Signed-off-by Simon Glass <[email protected]>---
drivers/pci/pci-uclass.c | 129 ++++++++++++++++++++++++++++++++++++++++++----- include/pci.h | 79 ++++++++++++++++++++++++++++- 2 files changed, 193 insertions(+), 15 deletions(-)drivers/pci/pci-uclass.c +116
-13@@ -353,6 +353,101 @@ int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf)return sub_bus; } +/** +* 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 bool pci_match_one_id (const struct pci_device_id *id, +const struct pci_device_id *find) +{ +if ((id->vendor ==PCI_ANY_ID || id->vendor == find->vendor) && + (id->device ==PCI_ANY_ID || id->device == find->device) && + (id->subvendor ==PCI_ANY_ID || id->subvendor == find->subvendor) && + (id->subdevice ==PCI_ANY_ID || id->subdevice == find->subdevice) && + !((id->class ^ find->class) & id->class_mask)) +return true; + +return false; +} + +/** +* pci_find_and_bind_driver() - Find and bind the right PCI driver +* +* This only looks at certain fields in the descriptor. +*/ +static int pci_find_and_bind_driver (struct udevice *parent, +struct pci_device_id *find_id,int devfn, +struct udevice **devp) +{ +struct pci_driver_entry *start, *entry; +const char *drv; +int n_ents; +int ret; +char name[30 ], *str; + + *devp =NULL ; + +debug ("%s: Searching for driver: vendor=%x, device=%x\n" , __func__, + find_id->vendor, find_id->device); + start = ll_entry_start(struct pci_driver_entry, pci_driver_entry); + n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry); +for (entry = start; entry != start + n_ents; entry++) { +const struct pci_device_id *id; +struct udevice *dev; +const struct driver *drv; + +for (id = entry->match; + id->vendor || id->subvendor || id->class_mask; + id++) { +if (!pci_match_one_id (id, find_id)) +continue ; + + drv = entry->driver; +/* +* We could pass the descriptor to the driver as +* platdata (instead of NULL) and allow its bind() +* method to return -ENOENT if it doesn't support this +* device. That way we could continue the search to +* find another driver. For now this doesn't seem +* necesssary, so just bind the first match. +*/ + ret =device_bind (parent, drv, drv->name,NULL ,-1 , + &dev); +if (ret) + goto error; +debug ("%s: Match found: %s\n" , __func__, drv->name); + dev->driver_data = find_id->driver_data; + *devp = dev; +return 0 ; + } + } + +/* Bind a generic driver so that the device can be used */ +sprintf (name,"pci_%x:%x.%x" , parent->seq,PCI_DEV (devfn), +PCI_FUNC (devfn)); + str =strdup (name); +if (!str) +return -ENOMEM ; + drv = (find_id->class >>8 ) ==PCI_CLASS_BRIDGE_PCI ?"pci_bridge_drv" : +"pci_generic_drv" ; + ret =device_bind_driver (parent, drv, str, devp); +if (ret) { +debug ("%s: Failed to bind generic driver: %d" , __func__, ret); +return ret; + } +debug ("%s: No match found: bound generic driver instead\n" , __func__); + +return 0 ; + +error: +debug ("%s: No match found: error %d\n" , __func__, ret); +return ret; +} +int pci_bind_bus_devices (struct udevice *bus) {ulong vendor, device;@@ -387,25 +482,33 @@ int pci_bind_bus_devices(struct udevice *bus) bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));pci_bus_read_config (bus, devfn,PCI_DEVICE_ID , &device,PCI_SIZE_16 ); -pci_bus_read_config (bus, devfn,PCI_CLASS_DEVICE , &class, -PCI_SIZE_16 ); +pci_bus_read_config (bus, devfn,PCI_CLASS_REVISION , &class, +PCI_SIZE_32 ); + class >>=8 ;/* Find this device in the device tree */ ret =pci_bus_find_devfn (bus, devfn, &dev); +/* Search for a driver */ +/* If nothing in the device tree, bind a generic device */ if (ret == -ENODEV ) { -char name[30 ], *str; -const char *drv; - -sprintf (name,"pci_%x:%x.%x" , bus->seq, -PCI_DEV (devfn),PCI_FUNC (devfn)); - str =strdup (name); -if (!str) -return -ENOMEM ; - drv = class ==PCI_CLASS_BRIDGE_PCI ? -"pci_bridge_drv" :"pci_generic_drv" ; - ret =device_bind_driver (bus, drv, str, &dev); +struct pci_device_id find_id; +ulong val; + +memset (&find_id,'\0' ,sizeof (find_id)); + find_id.vendor = vendor; + find_id.device = device; + find_id.class = class; +if ((header_type &0x7f ) ==PCI_HEADER_TYPE_NORMAL ) { +pci_bus_read_config (bus, devfn, +PCI_SUBSYSTEM_VENDOR_ID , + &val,PCI_SIZE_32 ); + find_id.subvendor = val &0xffff ; + find_id.subdevice = val >>16 ; + } + ret =pci_find_and_bind_driver (bus, &find_id, devfn, + &dev); }if (ret)return ret;include/pci.h +0
-0include/pci.h typedef int pci_dev_t; · line 475
Quoted 9 lines
include/pci.h +4
-1@@ -468,7 +468,10 @@ typedef int pci_dev_t;#define PCI_ANY_ID (~0)struct pci_device_id { -unsigned int vendor, device;/* Vendor and device ID or PCI_ANY_ID */ +unsigned int vendor, device;/* Vendor and device ID or PCI_ANY_ID */ +unsigned int subvendor, subdevice;/* Subsystem ID's or PCI_ANY_ID */ +unsigned int class, class_mask;/* (class,subclass,prog-if) triplet */ +unsigned long driver_data;/* Data private to the driver */ };Can we create another structure for dm? There are lots of codes which only defines vendor id and device id like below:
Quoted 6 lines
static struct
pci_device_idmmc_supported[] = {
{PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_TCF_SDIO_0}, {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_TCF_SDIO_1},
};Although compiler does not generate any error or warning, it is confusing.
I think the existing structure is for exactly this purpose, - I have just added a few new fields. Why do we want to change it? I also really want to use this name as it matches Linux.
Quoted 82 lines
Quoted 82 lines
include/pci.h +73
-1struct pci_controller ;@@ -1110,7 +1113,79 @@ struct dm_pci_emul_ops {int sandbox_pci_get_emul (struct udevice *bus,pci_dev_t find_devfn,struct udevice **emulp); -#endif +/** +* 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_SUB - macro used to describe a specific pci device with subsystem +* @vend: the 16 bit PCI Vendor ID +* @dev: the 16 bit PCI Device ID +* @subvend: the 16 bit PCI Subvendor ID +* @subdev: the 16 bit PCI Subdevice ID +* +* This macro is used to create a struct pci_device_id that matches a +* specific device with subsystem information. +*/ +#define PCI_DEVICE_SUB (vend, dev, subvend, subdev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = (subvend), .subdevice = (subdev) + +/** +* 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 + +/** +* struct pci_driver_entry - Matches a driver to its pci_device_id list +* @driver: Driver to use +* @match: List of match records for this driver, terminated by {} +*/ +struct pci_driver_entry { +struct driver *driver; +const struct pci_device_id *match; +}; + +#define U_BOOT_PCI_DEVICE (__name, __match) \ + ll_entry_declare(struct pci_driver_entry, __name, pci_driver_entry) = {\ + .driver = llsym(struct driver, __name, driver), \ + .match = __match, \ + } + +#endif /* CONFIG_DM_PCI */
Quoted 6 lines
include/pci.h struct dm_pci_emul_ops {
Quoted 3 lines
include/pci.h +0
-1#endif /* __ASSEMBLY__ */ #endif /* _PCI_H */ --Do you have plan to address the issue that dm pci cannot be used in the pre-reloc phase? Like we need pci uart as the U-Boot console.
Regards,
Simon
PATCH 5/18 dm: pci: Add support for PCI driver matching
Hi Simon,
Quoted 203 lines · Simon Glass
Hi Bin,
Quoted 200 lines · Bin Meng
Hi Simon,
Quoted 179 lines · Simon Glass
At present all PCI devices must be present in the device tree in order to be used. Many or most PCI devices don't require any configuration other than that which is done automatically by U-Boot. It is inefficent to add a node with nothing but a compatible string in order to get a device working.
Add a mechanism whereby PCI drivers can be declared along with the device parameters they support (vendor/device/class). When no suitable driver is found in the device tree the list of such devices is consulted to determine the correct driver. If this also fails, then a generic driver is used as before.
The mechanism used is very similar to that provided by Linux and the header file defintions are copied from Linux 4.1.
Signed-off-by Simon Glass <[email protected]>---
drivers/pci/pci-uclass.c | 129 ++++++++++++++++++++++++++++++++++++++++++----- include/pci.h | 79 ++++++++++++++++++++++++++++- 2 files changed, 193 insertions(+), 15 deletions(-)drivers/pci/pci-uclass.c +116
-13@@ -353,6 +353,101 @@ int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf)return sub_bus; } +/** +* 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 bool pci_match_one_id (const struct pci_device_id *id, +const struct pci_device_id *find) +{ +if ((id->vendor ==PCI_ANY_ID || id->vendor == find->vendor) && + (id->device ==PCI_ANY_ID || id->device == find->device) && + (id->subvendor ==PCI_ANY_ID || id->subvendor == find->subvendor) && + (id->subdevice ==PCI_ANY_ID || id->subdevice == find->subdevice) && + !((id->class ^ find->class) & id->class_mask)) +return true; + +return false; +} + +/** +* pci_find_and_bind_driver() - Find and bind the right PCI driver +* +* This only looks at certain fields in the descriptor. +*/ +static int pci_find_and_bind_driver (struct udevice *parent, +struct pci_device_id *find_id,int devfn, +struct udevice **devp) +{ +struct pci_driver_entry *start, *entry; +const char *drv; +int n_ents; +int ret; +char name[30 ], *str; + + *devp =NULL ; + +debug ("%s: Searching for driver: vendor=%x, device=%x\n" , __func__, + find_id->vendor, find_id->device); + start = ll_entry_start(struct pci_driver_entry, pci_driver_entry); + n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry); +for (entry = start; entry != start + n_ents; entry++) { +const struct pci_device_id *id; +struct udevice *dev; +const struct driver *drv; + +for (id = entry->match; + id->vendor || id->subvendor || id->class_mask; + id++) { +if (!pci_match_one_id (id, find_id)) +continue ; + + drv = entry->driver; +/* +* We could pass the descriptor to the driver as +* platdata (instead of NULL) and allow its bind() +* method to return -ENOENT if it doesn't support this +* device. That way we could continue the search to +* find another driver. For now this doesn't seem +* necesssary, so just bind the first match. +*/ + ret =device_bind (parent, drv, drv->name,NULL ,-1 , + &dev); +if (ret) + goto error; +debug ("%s: Match found: %s\n" , __func__, drv->name); + dev->driver_data = find_id->driver_data; + *devp = dev; +return 0 ; + } + } + +/* Bind a generic driver so that the device can be used */ +sprintf (name,"pci_%x:%x.%x" , parent->seq,PCI_DEV (devfn), +PCI_FUNC (devfn)); + str =strdup (name); +if (!str) +return -ENOMEM ; + drv = (find_id->class >>8 ) ==PCI_CLASS_BRIDGE_PCI ?"pci_bridge_drv" : +"pci_generic_drv" ; + ret =device_bind_driver (parent, drv, str, devp); +if (ret) { +debug ("%s: Failed to bind generic driver: %d" , __func__, ret); +return ret; + } +debug ("%s: No match found: bound generic driver instead\n" , __func__); + +return 0 ; + +error: +debug ("%s: No match found: error %d\n" , __func__, ret); +return ret; +} +int pci_bind_bus_devices (struct udevice *bus) {ulong vendor, device;@@ -387,25 +482,33 @@ int pci_bind_bus_devices(struct udevice *bus) bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));pci_bus_read_config (bus, devfn,PCI_DEVICE_ID , &device,PCI_SIZE_16 ); -pci_bus_read_config (bus, devfn,PCI_CLASS_DEVICE , &class, -PCI_SIZE_16 ); +pci_bus_read_config (bus, devfn,PCI_CLASS_REVISION , &class, +PCI_SIZE_32 ); + class >>=8 ;/* Find this device in the device tree */ ret =pci_bus_find_devfn (bus, devfn, &dev); +/* Search for a driver */ +/* If nothing in the device tree, bind a generic device */ if (ret == -ENODEV ) { -char name[30 ], *str; -const char *drv; - -sprintf (name,"pci_%x:%x.%x" , bus->seq, -PCI_DEV (devfn),PCI_FUNC (devfn)); - str =strdup (name); -if (!str) -return -ENOMEM ; - drv = class ==PCI_CLASS_BRIDGE_PCI ? -"pci_bridge_drv" :"pci_generic_drv" ; - ret =device_bind_driver (bus, drv, str, &dev); +struct pci_device_id find_id; +ulong val; + +memset (&find_id,'\0' ,sizeof (find_id)); + find_id.vendor = vendor; + find_id.device = device; + find_id.class = class; +if ((header_type &0x7f ) ==PCI_HEADER_TYPE_NORMAL ) { +pci_bus_read_config (bus, devfn, +PCI_SUBSYSTEM_VENDOR_ID , + &val,PCI_SIZE_32 ); + find_id.subvendor = val &0xffff ; + find_id.subdevice = val >>16 ; + } + ret =pci_find_and_bind_driver (bus, &find_id, devfn, + &dev); }if (ret)return ret;include/pci.h +0
-0include/pci.h typedef int pci_dev_t; · line 475
Quoted 9 lines
include/pci.h +4
-1@@ -468,7 +468,10 @@ typedef int pci_dev_t;#define PCI_ANY_ID (~0)struct pci_device_id { -unsigned int vendor, device;/* Vendor and device ID or PCI_ANY_ID */ +unsigned int vendor, device;/* Vendor and device ID or PCI_ANY_ID */ +unsigned int subvendor, subdevice;/* Subsystem ID's or PCI_ANY_ID */ +unsigned int class, class_mask;/* (class,subclass,prog-if) triplet */ +unsigned long driver_data;/* Data private to the driver */ };Can we create another structure for dm? There are lots of codes which only defines vendor id and device id like below:
static struct
pci_device_idmmc_supported[] = {
{PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_TCF_SDIO_0}, {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_TCF_SDIO_1},
};
Quoted 6 lines
Quoted 1 line
Although compiler does not generate any error or warning, it is confusing.
I think the existing structure is for exactly this purpose, - I have just added a few new fields. Why do we want to change it? I also really want to use this name as it matches Linux.
I mean it creates confusion if existing codes are unchanged, which makes me think it contains only a vendor id and a device id for each structure, but actually it has more members which are omitted. I would do:
static struct pci_device_id mmc_supported[] = {
{ .vendor = PCI_VENDOR_ID_INTEL, .device =PCI_DEVICE_ID_INTEL_TCF_SDIO_0 },
{ .vendor = PCI_VENDOR_ID_INTEL, .device =PCI_DEVICE_ID_INTEL_TCF_SDIO_1 },
And one more comment at the end.
Quoted 82 lines
Quoted 82 lines
Quoted 82 lines
include/pci.h +73
-1struct pci_controller ;@@ -1110,7 +1113,79 @@ struct dm_pci_emul_ops {int sandbox_pci_get_emul (struct udevice *bus,pci_dev_t find_devfn,struct udevice **emulp); -#endif +/** +* 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_SUB - macro used to describe a specific pci device with subsystem +* @vend: the 16 bit PCI Vendor ID +* @dev: the 16 bit PCI Device ID +* @subvend: the 16 bit PCI Subvendor ID +* @subdev: the 16 bit PCI Subdevice ID +* +* This macro is used to create a struct pci_device_id that matches a +* specific device with subsystem information. +*/ +#define PCI_DEVICE_SUB (vend, dev, subvend, subdev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = (subvend), .subdevice = (subdev) + +/** +* 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 + +/** +* struct pci_driver_entry - Matches a driver to its pci_device_id list +* @driver: Driver to use +* @match: List of match records for this driver, terminated by {} +*/ +struct pci_driver_entry { +struct driver *driver; +const struct pci_device_id *match; +}; + +#define U_BOOT_PCI_DEVICE (__name, __match) \ + ll_entry_declare(struct pci_driver_entry, __name, pci_driver_entry) = {\ + .driver = llsym(struct driver, __name, driver), \ + .match = __match, \ + } + +#endif /* CONFIG_DM_PCI */
Quoted 7 lines
Quoted 6 lines
include/pci.h struct dm_pci_emul_ops {
Quoted 3 lines
include/pci.h +0
-1#endif /* __ASSEMBLY__ */ #endif /* _PCI_H */ --Do you have plan to address the issue that dm pci cannot be used in the pre-reloc phase? Like we need pci uart as the U-Boot console.
Do you have plan to address the issue that dm pci cannot be used in the pre-reloc phase? Like we need pci uart as the U-Boot console.
Regards,
Bin
PATCH 5/18 dm: pci: Add support for PCI driver matching
Hi Bin,
Quoted 218 lines · Bin Meng
Hi Simon,
Quoted 203 lines · Simon Glass
Hi Bin,
Quoted 200 lines · Bin Meng
Hi Simon,
Quoted 179 lines · Simon Glass
At present all PCI devices must be present in the device tree in order to be used. Many or most PCI devices don't require any configuration other than that which is done automatically by U-Boot. It is inefficent to add a node with nothing but a compatible string in order to get a device working.
Add a mechanism whereby PCI drivers can be declared along with the device parameters they support (vendor/device/class). When no suitable driver is found in the device tree the list of such devices is consulted to determine the correct driver. If this also fails, then a generic driver is used as before.
The mechanism used is very similar to that provided by Linux and the header file defintions are copied from Linux 4.1.
Signed-off-by Simon Glass <[email protected]>---
drivers/pci/pci-uclass.c | 129 ++++++++++++++++++++++++++++++++++++++++++----- include/pci.h | 79 ++++++++++++++++++++++++++++- 2 files changed, 193 insertions(+), 15 deletions(-)drivers/pci/pci-uclass.c +116
-13@@ -353,6 +353,101 @@ int dm_pci_hose_probe_bus(struct pci_controller *hose, pci_dev_t bdf)return sub_bus; } +/** +* 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 bool pci_match_one_id (const struct pci_device_id *id, +const struct pci_device_id *find) +{ +if ((id->vendor ==PCI_ANY_ID || id->vendor == find->vendor) && + (id->device ==PCI_ANY_ID || id->device == find->device) && + (id->subvendor ==PCI_ANY_ID || id->subvendor == find->subvendor) && + (id->subdevice ==PCI_ANY_ID || id->subdevice == find->subdevice) && + !((id->class ^ find->class) & id->class_mask)) +return true; + +return false; +} + +/** +* pci_find_and_bind_driver() - Find and bind the right PCI driver +* +* This only looks at certain fields in the descriptor. +*/ +static int pci_find_and_bind_driver (struct udevice *parent, +struct pci_device_id *find_id,int devfn, +struct udevice **devp) +{ +struct pci_driver_entry *start, *entry; +const char *drv; +int n_ents; +int ret; +char name[30 ], *str; + + *devp =NULL ; + +debug ("%s: Searching for driver: vendor=%x, device=%x\n" , __func__, + find_id->vendor, find_id->device); + start = ll_entry_start(struct pci_driver_entry, pci_driver_entry); + n_ents = ll_entry_count(struct pci_driver_entry, pci_driver_entry); +for (entry = start; entry != start + n_ents; entry++) { +const struct pci_device_id *id; +struct udevice *dev; +const struct driver *drv; + +for (id = entry->match; + id->vendor || id->subvendor || id->class_mask; + id++) { +if (!pci_match_one_id (id, find_id)) +continue ; + + drv = entry->driver; +/* +* We could pass the descriptor to the driver as +* platdata (instead of NULL) and allow its bind() +* method to return -ENOENT if it doesn't support this +* device. That way we could continue the search to +* find another driver. For now this doesn't seem +* necesssary, so just bind the first match. +*/ + ret =device_bind (parent, drv, drv->name,NULL ,-1 , + &dev); +if (ret) + goto error; +debug ("%s: Match found: %s\n" , __func__, drv->name); + dev->driver_data = find_id->driver_data; + *devp = dev; +return 0 ; + } + } + +/* Bind a generic driver so that the device can be used */ +sprintf (name,"pci_%x:%x.%x" , parent->seq,PCI_DEV (devfn), +PCI_FUNC (devfn)); + str =strdup (name); +if (!str) +return -ENOMEM ; + drv = (find_id->class >>8 ) ==PCI_CLASS_BRIDGE_PCI ?"pci_bridge_drv" : +"pci_generic_drv" ; + ret =device_bind_driver (parent, drv, str, devp); +if (ret) { +debug ("%s: Failed to bind generic driver: %d" , __func__, ret); +return ret; + } +debug ("%s: No match found: bound generic driver instead\n" , __func__); + +return 0 ; + +error: +debug ("%s: No match found: error %d\n" , __func__, ret); +return ret; +} +int pci_bind_bus_devices (struct udevice *bus) {ulong vendor, device;@@ -387,25 +482,33 @@ int pci_bind_bus_devices(struct udevice *bus) bus->seq, bus->name, PCI_DEV(devfn), PCI_FUNC(devfn));pci_bus_read_config (bus, devfn,PCI_DEVICE_ID , &device,PCI_SIZE_16 ); -pci_bus_read_config (bus, devfn,PCI_CLASS_DEVICE , &class, -PCI_SIZE_16 ); +pci_bus_read_config (bus, devfn,PCI_CLASS_REVISION , &class, +PCI_SIZE_32 ); + class >>=8 ;/* Find this device in the device tree */ ret =pci_bus_find_devfn (bus, devfn, &dev); +/* Search for a driver */ +/* If nothing in the device tree, bind a generic device */ if (ret == -ENODEV ) { -char name[30 ], *str; -const char *drv; - -sprintf (name,"pci_%x:%x.%x" , bus->seq, -PCI_DEV (devfn),PCI_FUNC (devfn)); - str =strdup (name); -if (!str) -return -ENOMEM ; - drv = class ==PCI_CLASS_BRIDGE_PCI ? -"pci_bridge_drv" :"pci_generic_drv" ; - ret =device_bind_driver (bus, drv, str, &dev); +struct pci_device_id find_id; +ulong val; + +memset (&find_id,'\0' ,sizeof (find_id)); + find_id.vendor = vendor; + find_id.device = device; + find_id.class = class; +if ((header_type &0x7f ) ==PCI_HEADER_TYPE_NORMAL ) { +pci_bus_read_config (bus, devfn, +PCI_SUBSYSTEM_VENDOR_ID , + &val,PCI_SIZE_32 ); + find_id.subvendor = val &0xffff ; + find_id.subdevice = val >>16 ; + } + ret =pci_find_and_bind_driver (bus, &find_id, devfn, + &dev); }if (ret)return ret;include/pci.h +0
-0include/pci.h typedef int pci_dev_t; · line 475
Quoted 9 lines
include/pci.h +4
-1@@ -468,7 +468,10 @@ typedef int pci_dev_t;#define PCI_ANY_ID (~0)struct pci_device_id { -unsigned int vendor, device;/* Vendor and device ID or PCI_ANY_ID */ +unsigned int vendor, device;/* Vendor and device ID or PCI_ANY_ID */ +unsigned int subvendor, subdevice;/* Subsystem ID's or PCI_ANY_ID */ +unsigned int class, class_mask;/* (class,subclass,prog-if) triplet */ +unsigned long driver_data;/* Data private to the driver */ };Can we create another structure for dm? There are lots of codes which only defines vendor id and device id like below:
static struct
pci_device_idmmc_supported[] = {
{PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_TCF_SDIO_0}, {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_TCF_SDIO_1},
};Quoted 6 lines
Quoted 1 line
Although compiler does not generate any error or warning, it is confusing.
I think the existing structure is for exactly this purpose, - I have just added a few new fields. Why do we want to change it? I also really want to use this name as it matches Linux.
I mean it creates confusion if existing codes are unchanged, which makes me think it contains only a vendor id and a device id for each structure, but actually it has more members which are omitted. I would do:
Quoted 7 lines
static struct
pci_device_idmmc_supported[] = {
{ .vendor =PCI_VENDOR_ID_INTEL, .device =PCI_DEVICE_ID_INTEL_TCF_SDIO_0},
{ .vendor =PCI_VENDOR_ID_INTEL, .device =PCI_DEVICE_ID_INTEL_TCF_SDIO_1},And one more comment at the end.
OK I see. Well I can do this as a follow-on patch.
Quoted 91 lines
Quoted 83 lines
Quoted 83 lines
Quoted 83 lines
include/pci.h +73
-1struct pci_controller ;@@ -1110,7 +1113,79 @@ struct dm_pci_emul_ops {int sandbox_pci_get_emul (struct udevice *bus,pci_dev_t find_devfn,struct udevice **emulp); -#endif +/** +* 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_SUB - macro used to describe a specific pci device with subsystem +* @vend: the 16 bit PCI Vendor ID +* @dev: the 16 bit PCI Device ID +* @subvend: the 16 bit PCI Subvendor ID +* @subdev: the 16 bit PCI Subdevice ID +* +* This macro is used to create a struct pci_device_id that matches a +* specific device with subsystem information. +*/ +#define PCI_DEVICE_SUB (vend, dev, subvend, subdev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = (subvend), .subdevice = (subdev) + +/** +* 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 + +/** +* struct pci_driver_entry - Matches a driver to its pci_device_id list +* @driver: Driver to use +* @match: List of match records for this driver, terminated by {} +*/ +struct pci_driver_entry { +struct driver *driver; +const struct pci_device_id *match; +}; + +#define U_BOOT_PCI_DEVICE (__name, __match) \ + ll_entry_declare(struct pci_driver_entry, __name, pci_driver_entry) = {\ + .driver = llsym(struct driver, __name, driver), \ + .match = __match, \ + } + +#endif /* CONFIG_DM_PCI */ Quoted 7 lines
Quoted 6 lines
include/pci.h struct dm_pci_emul_ops {
Quoted 3 lines
include/pci.h +0
-1#endif /* __ASSEMBLY__ */ #endif /* _PCI_H */ --Do you have plan to address the issue that dm pci cannot be used in the pre-reloc phase? Like we need pci uart as the U-Boot console.
Quoted 2 lines
Do you have plan to address the issue that dm pci cannot be used in the pre-reloc phase? Like we need pci uart as the U-Boot console.
I suspect it can if we put it in the device tree. Is that good enough?
Applied to u-boot-dm.
Regards,
Simon
PATCH 6/18 dm: eth: Add driver-model support to the rtl8169 driver
In reply to Simon GlassThis driver is used by the Intel Minnowmax board. Convert it to driver model so it can use the new Ethernet implementation.
---
drivers/net/rtl8169.c | 236 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 187 insertions(+), 49 deletions(-)
drivers/net/rtl8169.c +187 -49
@@ -41,10 +41,13 @@* Modified to use le32_to_cpu and cpu_to_le32 properly */ #include <common.h> +#include <dm.h> #include <errno.h> #include <malloc.h> #include <net.h> +#ifndef CONFIG_DM_ETH #include <netdev.h> +#endif #include <asm/io.h> #include <pci.h>
@@ -281,6 +284,8 @@ struct RxDesc {u32 buf_Haddr; }; +static unsigned char rxdata[RX_BUF_LEN ]; +#define RTL8169_DESC_SIZE 16#if ARCH_DMA_MINALIGN >256
@@ -299,7 +304,8 @@ struct RxDesc {* the driver to allocate descriptors from a pool of non-cached memory. */ #if RTL8169_DESC_SIZE <ARCH_DMA_MINALIGN -#if !defined(CONFIG_SYS_NONCACHED_MEMORY ) && !defined(CONFIG_SYS_DCACHE_OFF ) +#if !defined(CONFIG_SYS_NONCACHED_MEMORY ) && \ + !defined(CONFIG_SYS_DCACHE_OFF ) && !defined(CONFIG_X86 )#warning cache-line size is larger than descriptor size#endif #endif
@@ -317,6 +323,7 @@ DEFINE_ALIGN_BUFFER(u8, txb, NUM_TX_DESC * RX_BUF_SIZE, RTL8169_ALIGN);DEFINE_ALIGN_BUFFER (u8, rxb,NUM_RX_DESC *RX_BUF_SIZE ,RTL8169_ALIGN );struct rtl8169_private { +ulong iobase;void *mmio_addr;/* memory map physical address */ int chipset;unsigned long cur_rx;/* Index into the Rx descriptor buffer of next Rx pkt. */
@@ -338,9 +345,9 @@ static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);static struct pci_device_id supported[] = { - {PCI_VENDOR_ID_REALTEK ,0x8167 }, - {PCI_VENDOR_ID_REALTEK ,0x8168 }, - {PCI_VENDOR_ID_REALTEK ,0x8169 }, + {PCI_DEVICE (PCI_VENDOR_ID_REALTEK ,0x8167 ) }, + {PCI_DEVICE (PCI_VENDOR_ID_REALTEK ,0x8168 ) }, + {PCI_DEVICE (PCI_VENDOR_ID_REALTEK ,0x8169 ) }, {} };
@@ -380,7 +387,7 @@ int mdio_read(int RegAddr)return value; } -static int rtl8169_init_board (struct eth_device *dev) +static int rtl8169_init_board (unsigned long dev_iobase,const char *name) {int i;u32 tmp;
@@ -388,7 +395,7 @@ static int rtl8169_init_board(struct eth_device *dev)#ifdef DEBUG_RTL8169 printf ("%s\n" , __FUNCTION__);#endif - ioaddr = dev->iobase; + ioaddr = dev_iobase;/* Soft reset the chip. */ RTL_W8 (ChipCmd, CmdReset);
@@ -412,7 +419,8 @@ static int rtl8169_init_board(struct eth_device *dev) }/* if unknown chip, assume array element #0, original RTL-8169 in this case */ -printf ("PCI device %s: unknown chip version, assuming RTL-8169\n" , dev->name); +printf ("PCI device %s: unknown chip version, assuming RTL-8169\n" , + name);printf ("PCI device: TxConfig = 0x%lX\n" , (unsigned long )RTL_R32 (TxConfig)); tpc->chipset =0 ;
@@ -504,7 +512,8 @@ static void rtl_flush_buffer(void *buf, size_t size)/************************************************************************** RECV - Receive a frame ***************************************************************************/ -static int rtl_recv (struct eth_device *dev) +static int rtl_recv_common (pci_dev_t bdf,unsigned long dev_iobase, +uchar **packetp) {/* return true if there's an ethernet packet ready to read */ /* nic->packet should contain data on return */
@@ -515,7 +524,7 @@ static int rtl_recv(struct eth_device *dev)#ifdef DEBUG_RTL8169_RX printf ("%s\n" , __FUNCTION__);#endif - ioaddr = dev->iobase; + ioaddr = dev_iobase; cur_rx = tpc->cur_rx;
@@ -523,7 +532,6 @@ static int rtl_recv(struct eth_device *dev)if ((le32_to_cpu (tpc->RxDescArray[cur_rx].status) & OWNbit) ==0 ) {if (!(le32_to_cpu (tpc->RxDescArray[cur_rx].status) & RxRES)) { -unsigned char rxdata[RX_BUF_LEN ]; length = (int ) (le32_to_cpu (tpc->RxDescArray[cur_rx]. status) &0x00001FFF ) -4 ;
@@ -536,17 +544,22 @@ static int rtl_recv(struct eth_device *dev)else tpc->RxDescArray[cur_rx].status =cpu_to_le32 (OWNbit +RX_BUF_SIZE ); - tpc->RxDescArray[cur_rx].buf_addr = -cpu_to_le32 (bus_to_phys (tpc->RxBufferRing[cur_rx])); + tpc->RxDescArray[cur_rx].buf_addr =cpu_to_le32 ( +pci_mem_to_phys (bdf, (pci_addr_t )(unsigned long ) + tpc->RxBufferRing[cur_rx]));rtl_flush_rx_desc (&tpc->RxDescArray[cur_rx]); - +#ifdef CONFIG_DM_ETH + *packetp = rxdata; +#else net_process_received_packet (rxdata, length); +#endif }else {puts ("Error Rx" ); + length = -EIO ; } cur_rx = (cur_rx +1 ) %NUM_RX_DESC ; tpc->cur_rx = cur_rx; -return 1 ; +return length; }else {ushort sts =RTL_R8 (IntrStatus);
@@ -557,11 +570,26 @@ static int rtl_recv(struct eth_device *dev)return (0 );/* initially as this is called to flush the input */ } +#ifdef CONFIG_DM_ETH +int rtl8169_eth_recv (struct udevice *dev,int flags,uchar **packetp) +{ +struct rtl8169_private *priv =dev_get_priv (dev); + +return rtl_recv_common (pci_get_bdf (dev), priv->iobase, packetp); +} +#else +static int rtl_recv (struct eth_device *dev) +{ +return rtl_recv_common ((pci_dev_t )dev->priv, dev->iobase,NULL ); +} +#endif /* nCONFIG_DM_ETH */ +#define HZ 1000/************************************************************************** SEND - Transmit a frame ***************************************************************************/ -static int rtl_send (struct eth_device *dev,void *packet,int length) +static int rtl_send_common (pci_dev_t bdf,unsigned long dev_iobase, +void *packet,int length) {/* send the packet to destination */
@@ -577,7 +605,7 @@ static int rtl_send(struct eth_device *dev, void *packet, int length)printf ("sending %d bytes\n" , len);#endif - ioaddr = dev->iobase; + ioaddr = dev_iobase;/* point to the current txb incase multiple tx_rings are used */ ptxb = tpc->Tx_skbuff[entry *MAX_ETH_FRAME_SIZE ];
@@ -588,7 +616,8 @@ static int rtl_send(struct eth_device *dev, void *packet, int length) ptxb[len++] ='\0' ; tpc->TxDescArray[entry].buf_Haddr =0 ; - tpc->TxDescArray[entry].buf_addr =cpu_to_le32 (bus_to_phys (ptxb)); + tpc->TxDescArray[entry].buf_addr =cpu_to_le32 ( +pci_mem_to_phys (bdf, (pci_addr_t )(unsigned long )ptxb));if (entry != (NUM_TX_DESC -1 )) { tpc->TxDescArray[entry].status = cpu_to_le32((OWNbit | FSbit | LSbit) |
@@ -625,7 +654,23 @@ static int rtl_send(struct eth_device *dev, void *packet, int length)return ret; } -static void rtl8169_set_rx_mode (struct eth_device *dev) +#ifdef CONFIG_DM_ETH +int rtl8169_eth_send (struct udevice *dev,void *packet,int length) +{ +struct rtl8169_private *priv =dev_get_priv (dev); + +return rtl_send_common (pci_get_bdf (dev), priv->iobase, packet, length); +} + +#else +static int rtl_send (struct eth_device *dev,void *packet,int length) +{ +return rtl_send_common ((pci_dev_t )dev->priv, dev->iobase, packet, + length); +} +#endif + +static void rtl8169_set_rx_mode (void ) {u32 mc_filter[2 ];/* Multicast hash filter */ int rx_mode;
@@ -648,7 +693,7 @@ static void rtl8169_set_rx_mode(struct eth_device *dev)RTL_W32 (MAR0 +4 , mc_filter[1 ]); } -static void rtl8169_hw_start (struct eth_device *dev) +static void rtl8169_hw_start (pci_dev_t bdf) {u32 i;
@@ -693,9 +738,11 @@ static void rtl8169_hw_start(struct eth_device *dev) tpc->cur_rx =0 ; -RTL_W32 (TxDescStartAddrLow,bus_to_phys (tpc->TxDescArray)); +RTL_W32 (TxDescStartAddrLow,pci_mem_to_phys (bdf, + (pci_addr_t )(unsigned long )tpc->TxDescArray));RTL_W32 (TxDescStartAddrHigh, (unsigned long )0 ); -RTL_W32 (RxDescStartAddrLow,bus_to_phys (tpc->RxDescArray)); +RTL_W32 (RxDescStartAddrLow,pci_mem_to_phys ( + bdf, (pci_addr_t )(unsigned long )tpc->RxDescArray));RTL_W32 (RxDescStartAddrHigh, (unsigned long )0 );/* RTL-8169sc/8110sc or later version */
@@ -707,7 +754,7 @@ static void rtl8169_hw_start(struct eth_device *dev)RTL_W32 (RxMissed,0 ); -rtl8169_set_rx_mode (dev); +rtl8169_set_rx_mode ();/* no early-rx interrupts */ RTL_W16 (MultiIntr,RTL_R16 (MultiIntr) &0xF000 );
@@ -717,7 +764,7 @@ static void rtl8169_hw_start(struct eth_device *dev)#endif } -static void rtl8169_init_ring (struct eth_device *dev) +static void rtl8169_init_ring (pci_dev_t bdf) {int i;
@@ -745,8 +792,8 @@ static void rtl8169_init_ring(struct eth_device *dev)cpu_to_le32 (OWNbit +RX_BUF_SIZE ); tpc->RxBufferRing[i] = &rxb[i *RX_BUF_SIZE ]; - tpc->RxDescArray[i].buf_addr = -cpu_to_le32 (bus_to_phys (tpc->RxBufferRing[i])); + tpc->RxDescArray[i].buf_addr =cpu_to_le32 (pci_mem_to_phys ( + bdf, (pci_addr_t )(unsigned long )tpc->RxBufferRing[i]));rtl_flush_rx_desc (&tpc->RxDescArray[i]); }
@@ -755,10 +802,7 @@ static void rtl8169_init_ring(struct eth_device *dev)#endif } -/************************************************************************** -RESET - Finish setting up the ethernet interface -***************************************************************************/ -static int rtl_reset (struct eth_device *dev,bd_t *bis) +static void rtl8169_common_start (pci_dev_t bdf,unsigned char *enetaddr) {int i;
@@ -767,30 +811,47 @@ static int rtl_reset(struct eth_device *dev, bd_t *bis)printf ("%s\n" , __FUNCTION__);#endif -rtl8169_init_ring (dev); -rtl8169_hw_start (dev); +rtl8169_init_ring (bdf); +rtl8169_hw_start (bdf);/* Construct a perfect filter frame with the mac address as first match * and broadcast for all others */ for (i =0 ; i <192 ; i++) txb[i] =0xFF ; - txb[0 ] = dev->enetaddr[0 ]; - txb[1 ] = dev->enetaddr[1 ]; - txb[2 ] = dev->enetaddr[2 ]; - txb[3 ] = dev->enetaddr[3 ]; - txb[4 ] = dev->enetaddr[4 ]; - txb[5 ] = dev->enetaddr[5 ]; + txb[0 ] = enetaddr[0 ]; + txb[1 ] = enetaddr[1 ]; + txb[2 ] = enetaddr[2 ]; + txb[3 ] = enetaddr[3 ]; + txb[4 ] = enetaddr[4 ]; + txb[5 ] = enetaddr[5 ];#ifdef DEBUG_RTL8169 printf ("%s elapsed time : %lu\n" , __func__,currticks ()-stime);#endif -return 0 ; } +#ifdef CONFIG_DM_ETH +static int rtl8169_eth_start (struct udevice *dev) +{ +struct eth_pdata *plat =dev_get_platdata (dev); + +rtl8169_common_start (pci_get_bdf (dev), plat->enetaddr); + +return 0 ; +} +#else /************************************************************************** -HALT - Turn off ethernet interface +RESET - Finish setting up the ethernet interface ***************************************************************************/ -static void rtl_halt (struct eth_device *dev) +static int rtl_reset (struct eth_device *dev,bd_t *bis) +{ +rtl8169_common_start ((pci_dev_t )dev->priv, dev->enetaddr); + +return 0 ; +} +#endif /* nCONFIG_DM_ETH */ + +static void rtl_halt_common (unsigned long dev_iobase) {int i;
@@ -798,7 +859,7 @@ static void rtl_halt(struct eth_device *dev)printf ("%s\n" , __FUNCTION__);#endif - ioaddr = dev->iobase; + ioaddr = dev_iobase;/* Stop the chip's Tx and Rx DMA processes. */ RTL_W8 (ChipCmd,0x00 );
@@ -813,13 +874,31 @@ static void rtl_halt(struct eth_device *dev) } } +#ifdef CONFIG_DM_ETH +void rtl8169_eth_stop (struct udevice *dev) +{ +struct rtl8169_private *priv =dev_get_priv (dev); + +rtl_halt_common (priv->iobase); +} +#else +/************************************************************************** +HALT - Turn off ethernet interface +***************************************************************************/ +static void rtl_halt (struct eth_device *dev) +{ +rtl_halt_common (dev->iobase); +} +#endif +/************************************************************************** INIT - Look for an adapter, this routine's visible to the outside ***************************************************************************/ #define board_found 1#define valid_link 0 -static int rtl_init (struct eth_device *dev,bd_t *bis) +static int rtl_init (unsigned long dev_ioaddr,const char *name, +unsigned char *enetaddr) {static int board_idx =-1 ;int i, rc;
@@ -828,33 +907,32 @@ static int rtl_init(struct eth_device *dev, bd_t *bis)#ifdef DEBUG_RTL8169 printf ("%s\n" , __FUNCTION__);#endif - - ioaddr = dev->iobase; + ioaddr = dev_ioaddr; board_idx++;/* point to private storage */ tpc = &tpx; - rc =rtl8169_init_board (dev); + rc =rtl8169_init_board (ioaddr, name);if (rc)return rc;/* Get MAC address. FIXME: read EEPROM */ for (i =0 ; i <MAC_ADDR_LEN ; i++) - dev->enetaddr[i] =RTL_R8 (MAC0 + i); + enetaddr[i] =RTL_R8 (MAC0 + i);#ifdef DEBUG_RTL8169 printf ("chipset = %d\n" , tpc->chipset);printf ("MAC Address" );for (i =0 ; i <MAC_ADDR_LEN ; i++) -printf (":%02x" , dev->enetaddr[i]); +printf (":%02x" , enetaddr[i]);putc ('\n' );#endif #ifdef DEBUG_RTL8169 /* Print out some hardware info */ -printf ("%s: at ioaddr 0x%lx\n" , dev->name, ioaddr); +printf ("%s: at ioaddr 0x%lx\n" , name, ioaddr);#endif /* if TBI is not endbled */
@@ -964,6 +1042,7 @@ static int rtl_init(struct eth_device *dev, bd_t *bis)return 0 ; } +#ifndef CONFIG_DM_ETH int rtl8169_initialize (bd_t *bis) {pci_dev_t devno;
@@ -1014,7 +1093,7 @@ int rtl8169_initialize(bd_t *bis) dev->send = rtl_send; dev->recv = rtl_recv; - err =rtl_init (dev, bis); + err =rtl_init (dev->iobase, dev->name, dev->enetaddr);if (err <0 ) {printf (pr_fmt ("failed to initialize card: %d\n" ), err);free (dev);
@@ -1027,3 +1106,62 @@ int rtl8169_initialize(bd_t *bis) }return card_number; } +#endif + +#ifdef CONFIG_DM_ETH +static int rtl8169_eth_probe (struct udevice *dev) +{ +struct pci_child_platdata *pplat =dev_get_parent_platdata (dev); +struct rtl8169_private *priv =dev_get_priv (dev); +struct eth_pdata *plat =dev_get_platdata (dev); +u32 iobase; +int region; +int ret; + +debug ("rtl8169: REALTEK RTL8169 @0x%x\n" , iobase); +switch (pplat->device) { +case 0x8168 : + region =2 ; +break ; +default : + region =1 ; +break ; + } +pci_read_config32 (pci_get_bdf (dev),PCI_BASE_ADDRESS_0 + region *4 , + &iobase); + iobase &= ~0xf ; + priv->iobase = (int )pci_mem_to_phys (pci_get_bdf (dev), iobase); + + ret =rtl_init (priv->iobase, dev->name, plat->enetaddr); +if (ret <0 ) { +printf (pr_fmt ("failed to initialize card: %d\n" ), ret); +return ret; + } + +return 0 ; +} + +static const struct eth_ops rtl8169_eth_ops = { + .start = rtl8169_eth_start, + .send = rtl8169_eth_send, + .recv = rtl8169_eth_recv, + .stop = rtl8169_eth_stop, +}; + +static const struct udevice_id rtl8169_eth_ids[] = { + { .compatible ="realtek,rtl8169" }, + { } +}; + +U_BOOT_DRIVER (eth_rtl8169) = { + .name ="eth_rtl8169" , + .id =UCLASS_ETH , + .of_match = rtl8169_eth_ids, + .probe = rtl8169_eth_probe, + .ops = &rtl8169_eth_ops, + .priv_auto_alloc_size =sizeof (struct rtl8169_private ), + .platdata_auto_alloc_size =sizeof (struct eth_pdata ), +}; + +U_BOOT_PCI_DEVICE (eth_rtl8169, supported); +#endif
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 6/18 dm: eth: Add driver-model support to the rtl8169 driver
Quoted 8 lines · Simon Glass
This driver is used by the Intel Minnowmax board. Convert it to driver model so it can use the new Ethernet implementation.
Signed-off-by Simon Glass <[email protected]>---
drivers/net/rtl8169.c | 236 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 187 insertions(+), 49 deletions(-)
Applied to u-boot-dm.
PATCH 7/18 dm: pci: Add a function to get the BDF for a device
In reply to Simon GlassIt is useful to be able to find the full PCI address (bus, device and function) for a PCI device. Add a function to provide this.
Adjust the existing code to use this.
---
drivers/pci/pci-uclass.c | 15 +++++++++------ drivers/pci/pci_compat.c | 8 ++------ include/pci.h | 8 ++++++++ 3 files changed, 19 insertions(+), 12 deletions(-)
drivers/pci/pci-uclass.c +9 -6
@@ -30,6 +30,14 @@ struct pci_controller *pci_bus_to_hose(int busnum)return dev_get_uclass_priv (bus); } +pci_dev_t pci_get_bdf (struct udevice *dev) +{ +struct pci_child_platdata *pplat =dev_get_parent_platdata (dev); +struct udevice *bus = dev->parent; + +return PCI_ADD_BUS (bus->seq, pplat->devfn); +} +/** * pci_get_bus_max() - returns the bus number of the last active bus *
@@ -295,19 +303,14 @@ int pci_auto_config_devices(struct udevice *bus)for (ret =device_find_first_child (bus, &dev); !ret && dev; ret =device_find_next_child (&dev)) { -struct pci_child_platdata *pplat;struct pci_controller *ctlr_hose; - - pplat =dev_get_parent_platdata (dev);unsigned int max_bus; -pci_dev_t bdf; - bdf =PCI_ADD_BUS (bus->seq, pplat->devfn);debug ("%s: device %s\n" , __func__, dev->name);/* The root controller has the region information */ ctlr_hose = hose->ctlr->uclass_priv; - max_bus =pciauto_config_device (ctlr_hose, bdf); + max_bus =pciauto_config_device (ctlr_hose,pci_get_bdf (dev)); sub_bus =max (sub_bus, max_bus); }debug ("%s: done\n" , __func__);
drivers/pci/pci_compat.c +2 -6
@@ -31,13 +31,9 @@ PCI_HOSE_OP(write, dword, 32, u32)pci_dev_t pci_find_devices (struct pci_device_id *ids,int index) { -struct pci_child_platdata *pplat; -struct udevice *bus, *dev; +struct udevice *dev;if (pci_find_device_id (ids, index, &dev))return -1 ; - bus = dev->parent; - pplat =dev_get_parent_platdata (dev); - -return PCI_ADD_BUS (bus->seq, pplat->devfn); +return pci_get_bdf (dev); }
include/pci.h +8 -0
@@ -817,6 +817,14 @@ struct dm_pci_ops {#define pci_get_ops (dev) ((struct dm_pci_ops *)(dev)->driver->ops)/** +* pci_get_bdf() - Get the BDF value for a device +* +* @dev: Device to check +* @return bus/device/function value (see PCI_BDF()) +*/ +pci_dev_t pci_get_bdf (struct udevice *dev); + +/** * pci_bind_bus_devices() - scan a PCI bus and bind devices * * Scan a PCI bus looking for devices. Bind each one that is found. If
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 7/18 dm: pci: Add a function to get the BDF for a device
Quoted 5 lines · Simon Glass
It is useful to be able to find the full PCI address (bus, device and function) for a PCI device. Add a function to provide this.
Adjust the existing code to use this.
Quoted 7 lines
Signed-off-by Simon Glass <[email protected]>---
drivers/pci/pci-uclass.c | 15 +++++++++------ drivers/pci/pci_compat.c | 8 ++------ include/pci.h | 8 ++++++++ 3 files changed, 19 insertions(+), 12 deletions(-)
Applied to u-boot-dm.
PATCH 8/18 dm: usb: Correct the struct usb_driver_entry comment
In reply to Simon GlassThe function documentation is incorrect. Fix it.
---
include/usb.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
include/usb.h +2 -2
@@ -493,8 +493,8 @@ struct usb_device_id {/** * struct usb_driver_entry - Matches a driver to its usb_device_ids -* @compatible: Compatible string -* @data: Data for this compatible string +* @driver: Driver to use +* @match: List of match records for this driver, terminated by {} */ struct usb_driver_entry {struct driver *driver;
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 8/18 dm: usb: Correct the struct usb_driver_entry comment
Quoted 3 lines · Simon Glass
The function documentation is incorrect. Fix it.
Signed-off-by Simon Glass <[email protected]>
Best regards,
Marek Vasut
PATCH 8/18 dm: usb: Correct the struct usb_driver_entry comment
Quoted 9 lines · Marek Vasut
Quoted 3 lines · Simon Glass
The function documentation is incorrect. Fix it.
Signed-off-by Simon Glass <[email protected]>Acked-by Marek Vasut <[email protected]>Best regards,
Marek Vasut
Applied to u-boot-dm.
PATCH 9/18 dm: usb: Avoid using USB ethernet with CONFIG_DM_USB and no DM_ETH
In reply to Simon GlassIf driver model is used for Ethernet then USB Ethernet does not build. This can be made to work with driver model is used for USB also. Add #ifdef logic to make this clear when building.
---
common/cmd_usb.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
common/cmd_usb.c +7 -5
@@ -23,7 +23,7 @@static int usb_stor_curr_dev =-1 ;/* current device */ #endif #ifdef CONFIG_USB_HOST_ETHER -static int usb_ether_curr_dev =-1 ;/* current ethernet device */ +static int __maybe_unused usb_ether_curr_dev =-1 ;/* current ethernet device */ #endif /* some display routines (info command) */
@@ -526,14 +526,16 @@ static void do_usb_start(void)/* Driver model will probe the devices as they are found */ #ifndef CONFIG_DM_USB -#ifdef CONFIG_USB_STORAGE +# ifdef CONFIG_USB_STORAGE /* try to recognize storage devices immediately */ usb_stor_curr_dev =usb_stor_scan (1 ); -#endif -#endif -#ifdef CONFIG_USB_HOST_ETHER +# endif +# ifdef CONFIG_DM_ETH +# warning "You must use CONFIG_DM_USB if you want to use CONFIG_USB_HOST_ETHER with CONFIG_DM_ETH" +# elif defined(CONFIG_USB_HOST_ETHER )/* try to recognize ethernet devices immediately */ usb_ether_curr_dev =usb_host_eth_scan (1 ); +# endif #endif #ifdef CONFIG_USB_KEYBOARD drv_usb_kbd_init ();
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 9/18 dm: usb: Avoid using USB ethernet with CONFIG_DM_USB and no DM_ETH
Quoted 5 lines · Simon Glass
If driver model is used for Ethernet then USB Ethernet does not build. This can be made to work with driver model is used for USB also. Add #ifdef logic to make this clear when building.
Signed-off-by Simon Glass <[email protected]>
Well ew, but OK.
Best regards,
Marek Vasut
PATCH 9/18 dm: usb: Avoid using USB ethernet with CONFIG_DM_USB and no DM_ETH
Quoted 5 lines · Marek Vasut
Quoted 4 lines · Simon Glass
If driver model is used for Ethernet then USB Ethernet does not build. This can be made to work with driver model is used for USB also. Add #ifdef logic to make this clear when building.
Quoted 8 lines
Quoted 1 line
Signed-off-by Simon Glass <[email protected]>Well ew, but OK.
Reviewed-by Marek Vasut <[email protected]>Best regards,
Marek Vasut
I squashed this in with my later patch
http://patchwork.ozlabs.org/patch/492686/ which should reduce the ew. But ultimate we should try to get all of this to driver model.
Applied to u-boot-dm.
PATCH 10/18 dm: eth: Avoid blocking on packet reception
In reply to Simon GlassSome devices can take a long time to work out whether they have a new packet or now. For example the ASIX USB Ethernet dongle can take 5 seconds to do this, since it waits until it gets a new packet on the wire before allowing the USB bulk read packet to be submitted.
At present with driver mode the Ethernet receive code reads 32 packets. This can take a very long time if we must wait for all 32 packets. The old code (before driver model) worked by reading a single set of packets from the USB device, then processing all the packets with in. It would be nice to use the same behaviour with driver model.
Add a flag to the receive method which indicates that the driver should try to find a packet if available, by consulting the hardware. When the flag is not set, it should just return any packet data it has already received. If there is none, it should return -EAGAIN so that the loop will terminate.
---
drivers/net/designware.c | 2 +- drivers/net/sandbox-raw.c | 2 +- drivers/net/sandbox.c | 2 +- drivers/net/sunxi_emac.c | 2 +- include/net.h | 10 +++++++++- net/eth.c | 5 ++++- 6 files changed, 17 insertions(+), 6 deletions(-)
drivers/net/designware.c +1 -1
@@ -522,7 +522,7 @@ static int designware_eth_send(struct udevice *dev, void *packet, int length)return _dw_eth_send (priv, packet, length); } -static int designware_eth_recv (struct udevice *dev,uchar **packetp) +static int designware_eth_recv (struct udevice *dev,int flags,uchar **packetp) {struct dw_eth_dev *priv =dev_get_priv (dev);
drivers/net/sandbox-raw.c +1 -1
@@ -65,7 +65,7 @@ static int sb_eth_raw_send(struct udevice *dev, void *packet, int length)return sandbox_eth_raw_os_send (packet, length, priv); } -static int sb_eth_raw_recv (struct udevice *dev,uchar **packetp) +static int sb_eth_raw_recv (struct udevice *dev,int flags,uchar **packetp) {struct eth_pdata *pdata =dev_get_platdata (dev);struct eth_sandbox_raw_priv *priv =dev_get_priv (dev);
drivers/net/sandbox.c +1 -1
@@ -152,7 +152,7 @@ static int sb_eth_send(struct udevice *dev, void *packet, int length)return 0 ; } -static int sb_eth_recv (struct udevice *dev,uchar **packetp) +static int sb_eth_recv (struct udevice *dev,int flags,uchar **packetp) {struct eth_sandbox_priv *priv =dev_get_priv (dev);
drivers/net/sunxi_emac.c +1 -1
@@ -527,7 +527,7 @@ static int sunxi_emac_eth_send(struct udevice *dev, void *packet, int length)return _sunxi_emac_eth_send (priv, packet, length); } -static int sunxi_emac_eth_recv (struct udevice *dev,uchar **packetp) +static int sunxi_emac_eth_recv (struct udevice *dev,int flags,uchar **packetp) {struct emac_eth_dev *priv =dev_get_priv (dev);int rx_len;
include/net.h +9 -1
@@ -93,6 +93,14 @@ struct eth_pdata {int phy_interface; }; +enum eth_recv_flags { +/* +* Check hardware device for new packets (otherwise only return those +* which are already in the memory buffer ready to process) +*/ +ETH_RECV_CHECK_DEVICE =1 <<0 , +}; +/** * struct eth_ops - functions of Ethernet MAC controllers *
@@ -120,7 +128,7 @@ struct eth_pdata {struct eth_ops {int (*start)(struct udevice *dev);int (*send)(struct udevice *dev,void *packet,int length); -int (*recv)(struct udevice *dev,uchar **packetp); +int (*recv)(struct udevice *dev,int flags,uchar **packetp);int (*free_pkt)(struct udevice *dev,uchar *packet,int length);void (*stop)(struct udevice *dev);#ifdef CONFIG_MCAST_TFTP
net/eth.c +4 -1
@@ -404,6 +404,7 @@ int eth_rx(void) {struct udevice *current;uchar *packet; +int flags;int ret;int i;
@@ -415,8 +416,10 @@ int eth_rx(void)return -EINVAL ;/* Process up to 32 packets@one time */ + flags =ETH_RECV_CHECK_DEVICE ;for (i =0 ; i <32 ; i++) { - ret =eth_get_ops (current)->recv (current, &packet); + ret =eth_get_ops (current)->recv (current, flags, &packet); + flags =0 ;if (ret >0 )net_process_received_packet (packet, ret);if (ret >=0 &ð_get_ops (current)->free_pkt)
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 10/18 dm: eth: Avoid blocking on packet reception
Quoted 19 lines · Simon Glass
Some devices can take a long time to work out whether they have a new packet or now. For example the ASIX USB Ethernet dongle can take 5 seconds to do this, since it waits until it gets a new packet on the wire before allowing the USB bulk read packet to be submitted.
At present with driver mode the Ethernet receive code reads 32 packets. This can take a very long time if we must wait for all 32 packets. The old code (before driver model) worked by reading a single set of packets from the USB device, then processing all the packets with in. It would be nice to use the same behaviour with driver model.
Add a flag to the receive method which indicates that the driver should try to find a packet if available, by consulting the hardware. When the flag is not set, it should just return any packet data it has already received. If there is none, it should return
-EAGAINso that the loop will terminate.Signed-off-by Simon Glass <[email protected]>---
Quoted 7 lines
drivers/net/designware.c | 2 +- drivers/net/sandbox-raw.c | 2 +- drivers/net/sandbox.c | 2 +- drivers/net/sunxi_emac.c | 2 +- include/net.h | 10 +++++++++- net/eth.c | 5 ++++- 6 files changed, 17 insertions(+), 6 deletions(-)
Applied to u-boot-dm.
PATCH 10/18 dm: eth: Avoid blocking on packet reception
In reply to Simon GlassHi Simon,
Quoted 11 lines · Simon Glass
Some devices can take a long time to work out whether they have a new packet or now. For example the ASIX USB Ethernet dongle can take 5 seconds to do this, since it waits until it gets a new packet on the wire before allowing the USB bulk read packet to be submitted.
At present with driver mode the Ethernet receive code reads 32 packets. This can take a very long time if we must wait for all 32 packets. The old code (before driver model) worked by reading a single set of packets from the USB device, then processing all the packets with in. It would be nice to use the same behaviour with driver model.
Quoted 7 lines
Add a flag to the receive method which indicates that the driver should try to find a packet if available, by consulting the hardware. When the flag is not set, it should just return any packet data it has already received. If there is none, it should return
-EAGAINso that the loop will terminate.Signed-off-by Simon Glass <[email protected]>---
PATCH 11/18 dm: usb: eth: Support driver model with USB Ethernet
In reply to Simon GlassAt present USB Ethernet does not work with CONFIG_DM_ETH. Add driver model support to this feature, so that it can work alongside other Ethernet devices with driver model.
It was found that quite a bit of code is common in most of the USB Ethernet drivers. Add this code to the common layer to reduce the amount of duplicate code needed in USB Ethernet drivers when CONFIG_DM_ETH is used.
---
common/cmd_usb.c | 2 +- drivers/usb/eth/usb_ether.c | 127 ++++++++++++++++++++++++++++++++++++++++++++ include/usb_ether.h | 89 +++++++++++++++++++++++++++---- 3 files changed, 206 insertions(+), 12 deletions(-)
common/cmd_usb.c +1 -1
@@ -22,7 +22,7 @@#ifdef CONFIG_USB_STORAGE static int usb_stor_curr_dev =-1 ;/* current device */ #endif -#ifdef CONFIG_USB_HOST_ETHER +#if defined(CONFIG_USB_HOST_ETHER ) && !defined(CONFIG_DM_ETH )static int __maybe_unused usb_ether_curr_dev =-1 ;/* current ethernet device */ #endif
drivers/usb/eth/usb_ether.c +127 -0
141 lines not on this page · raw message
include/usb_ether.h +78 -11
108 lines not on this page · raw message
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 11/18 dm: usb: eth: Support driver model with USB Ethernet
Quoted 9 lines · Simon Glass
At present USB Ethernet does not work with
CONFIG_DM_ETH. Add driver model support to this feature, so that it can work alongside other Ethernet devices with driver model.It was found that quite a bit of code is common in most of the USB Ethernet drivers. Add this code to the common layer to reduce the amount of duplicate code needed in USB Ethernet drivers when
CONFIG_DM_ETHis used.Signed-off-by Simon Glass <[email protected]>
Best regards,
Marek Vasut
PATCH 11/18 dm: usb: eth: Support driver model with USB Ethernet
Quoted 9 lines · Marek Vasut
Quoted 8 lines · Simon Glass
At present USB Ethernet does not work with
CONFIG_DM_ETH. Add driver model support to this feature, so that it can work alongside other Ethernet devices with driver model.It was found that quite a bit of code is common in most of the USB Ethernet drivers. Add this code to the common layer to reduce the amount of duplicate code needed in USB Ethernet drivers when
CONFIG_DM_ETHis used.
Quoted 6 lines
Quoted 1 line
Signed-off-by Simon Glass <[email protected]>Reviewed-by Marek Vasut <[email protected]>Best regards,
Marek Vasut
Applied to u-boot-dm.
PATCH 12/18 dm: usb: Adjust the USB_DEVICE() macro naming
In reply to Simon GlassIn Linux USB_DEVICE() is used to declare a USB device by vendor/device ID. We should follow the same convention in U-Boot. Rename the existing USB_DEVICE() macro to U_BOOT_USB_DEVICE() and bring in the USB_DEVICE() macro from Linux for use in U-Boot.
---
common/usb_hub.c | 2 +- common/usb_kbd.c | 4 ++-- common/usb_storage.c | 2 +- drivers/usb/Kconfig | 4 ++-- drivers/usb/eth/usb_ether.c | 4 ++-- include/usb.h | 18 +++++++++++++++++- 6 files changed, 25 insertions(+), 9 deletions(-)
common/usb_hub.c +1 -1
@@ -652,6 +652,6 @@ static const struct usb_device_id hub_id_table[] = { { } /* Terminating entry */ }; -USB_DEVICE (usb_generic_hub, hub_id_table); +U_BOOT_USB_DEVICE (usb_generic_hub, hub_id_table);#endif
common/usb_kbd.c +2 -2
@@ -540,8 +540,8 @@ int drv_usb_kbd_init(void)debug ("%s: Probing for keyboard\n" , __func__);#ifdef CONFIG_DM_USB /* -* TODO: We should add USB_DEVICE() declarations to each USB ethernet -* driver and then most of this file can be removed. +* TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB +* keyboard driver and then most of this file can be removed. */ struct udevice *bus;struct uclass *uc;
common/usb_storage.c +1 -1
@@ -1442,6 +1442,6 @@ static const struct usb_device_id mass_storage_id_table[] = { { } /* Terminating entry */ }; -USB_DEVICE (usb_mass_storage, mass_storage_id_table); +U_BOOT_USB_DEVICE (usb_mass_storage, mass_storage_id_table);#endif
drivers/usb/Kconfig +2 -2
@@ -46,8 +46,8 @@ config DM_USB Much of the code is shared but with this option enabled the USB uclass takes care of device enumeration. USB devices can be - declared with the USB_DEVICE() macro and will be automatically - probed when found on the bus. + declared with the U_BOOT_USB_DEVICE() macro and will be + automatically probed when found on the bus. source "drivers/usb/host/Kconfig"
drivers/usb/eth/usb_ether.c +2 -2
@@ -266,8 +266,8 @@ int usb_host_eth_scan(int mode) usb_max_eth_dev =0 ;#ifdef CONFIG_DM_USB /* -* TODO: We should add USB_DEVICE() declarations to each USB ethernet -* driver and then most of this file can be removed. +* TODO: We should add U_BOOT_USB_DEVICE() declarations to each USB +* Ethernet driver and then most of this file can be removed. */ struct udevice *bus;struct uclass *uc;
include/usb.h +17 -1
@@ -501,7 +501,23 @@ struct usb_driver_entry {const struct usb_device_id *match; }; -#define USB_DEVICE (__name, __match) \ +#define USB_DEVICE_ID_MATCH_DEVICE \ + (USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT) + +/** +* USB_DEVICE - macro used to describe a specific usb device +* @vend: the 16 bit USB Vendor ID +* @prod: the 16 bit USB Product ID +* +* This macro is used to create a struct usb_device_id that matches a +* specific device. +*/ +#define USB_DEVICE (vend, prod) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \ + .idVendor = (vend), \ + .idProduct = (prod) + +#define U_BOOT_USB_DEVICE (__name, __match) \ ll_entry_declare(struct usb_driver_entry, __name, usb_driver_entry) = {\ .driver = llsym(struct driver, __name, driver), \ .match = __match, \
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 12/18 dm: usb: Adjust the USB_DEVICE() macro naming
Quoted 6 lines · Simon Glass
In Linux
USB_DEVICE()is used to declare a USB device by vendor/device ID. We should follow the same convention in U-Boot. Rename the existingUSB_DEVICE()macro toU_BOOT_USB_DEVICE()and bring in theUSB_DEVICE()macro from Linux for use in U-Boot.Signed-off-by Simon Glass <[email protected]>
Best regards,
Marek Vasut
PATCH 12/18 dm: usb: Adjust the USB_DEVICE() macro naming
Quoted 6 lines · Marek Vasut
Quoted 5 lines · Simon Glass
In Linux
USB_DEVICE()is used to declare a USB device by vendor/device ID. We should follow the same convention in U-Boot. Rename the existingUSB_DEVICE()macro toU_BOOT_USB_DEVICE()and bring in theUSB_DEVICE()macro from Linux for use in U-Boot.
Quoted 6 lines
Quoted 1 line
Signed-off-by Simon Glass <[email protected]>Acked-by Marek Vasut <[email protected]>Best regards,
Marek Vasut
Applied to u-boot-dm.
PATCH 13/18 x86: minnowmax: Drop the cache line size hack
In reply to Simon GlassNow that the RTL8169 driver warning is fixed we can drop this. The incorrect value is causing problems with USB EHCI.
---
include/configs/minnowmax.h | 3 --- 1 file changed, 3 deletions(-)
include/configs/minnowmax.h +0 -3
@@ -63,9 +63,6 @@#define CONFIG_FIT_SIGNATURE #define CONFIG_RSA -/* Avoid a warning in the Realtek Ethernet driver */ -#define CONFIG_SYS_CACHELINE_SIZE 16 -#define CONFIG_ENV_SECT_SIZE 0x1000#define CONFIG_ENV_OFFSET 0x007fe000
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 13/18 x86: minnowmax: Drop the cache line size hack
Quoted 14 lines · Simon Glass
Now that the RTL8169 driver warning is fixed we can drop this. The incorrect value is causing problems with USB EHCI.
Signed-off-by Simon Glass <[email protected]>---
include/configs/minnowmax.h | 3 --- 1 file changed, 3 deletions(-)include/configs/minnowmax.h +0
-0
include/configs/minnowmax.h
Quoted 10 lines
include/configs/minnowmax.h +0
-4@@ -63,9 +63,6 @@#define CONFIG_FIT_SIGNATURE #define CONFIG_RSA -/* Avoid a warning in the Realtek Ethernet driver */ -#define CONFIG_SYS_CACHELINE_SIZE 16 -#define CONFIG_ENV_SECT_SIZE 0x1000#define CONFIG_ENV_OFFSET 0x007fe000 --
PATCH 13/18 x86: minnowmax: Drop the cache line size hack
Quoted 24 lines · Bin Meng
Quoted 23 lines · Simon Glass
Now that the RTL8169 driver warning is fixed we can drop this. The incorrect value is causing problems with USB EHCI.
Signed-off-by Simon Glass <[email protected]>---
include/configs/minnowmax.h | 3 --- 1 file changed, 3 deletions(-)include/configs/minnowmax.h +0
-3@@ -63,9 +63,6 @@#define CONFIG_FIT_SIGNATURE #define CONFIG_RSA -/* Avoid a warning in the Realtek Ethernet driver */ -#define CONFIG_SYS_CACHELINE_SIZE 16 -#define CONFIG_ENV_SECT_SIZE 0x1000#define CONFIG_ENV_OFFSET 0x007fe000
Quoted 3 lines
Quoted 1 line
--
Reviewed-by Bin Meng <[email protected]>
Applied to u-boot-dm.
PATCH 14/18 dm: usb: Add driver-model support to ehci-pci
In reply to Simon GlassSupport driver model in this driver. This uses the normal USB driver search mechanism. Any EHCI controllers will be set up as they are found during usb_init().
---
drivers/usb/host/ehci-pci.c | 97 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 20 deletions(-)
drivers/usb/host/ehci-pci.c +77 -20
@@ -6,12 +6,45 @@*/ #include <common.h> +#include <dm.h> #include <errno.h> #include <pci.h> #include <usb.h> #include "ehci.h" +/* Information about a USB port */ +struct ehci_pci_priv { +struct ehci_ctrl ehci; +}; + +static void ehci_pci_common_init (pci_dev_t pdev,struct ehci_hccr **ret_hccr, +struct ehci_hcor **ret_hcor) +{ +struct ehci_hccr *hccr; +struct ehci_hcor *hcor; +uint32_t cmd; + + hccr = (struct ehci_hccr *)pci_map_bar (pdev, +PCI_BASE_ADDRESS_0 ,PCI_REGION_MEM ); + hcor = (struct ehci_hcor *)((uint32_t ) hccr + +HC_LENGTH (ehci_readl (&hccr->cr_capbase))); + +debug ("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n" , + (uint32_t )hccr, (uint32_t )hcor, + (uint32_t )HC_LENGTH (ehci_readl (&hccr->cr_capbase))); + + *ret_hccr = hccr; + *ret_hcor = hcor; + +/* enable busmaster */ +pci_read_config_dword (pdev,PCI_COMMAND , &cmd); + cmd |=PCI_COMMAND_MASTER ; +pci_write_config_dword (pdev,PCI_COMMAND , cmd); +} + +#ifndef CONFIG_DM_USB +#ifdef CONFIG_PCI_EHCI_DEVICE static struct pci_device_id ehci_pci_ids[] = { /* Please add supported PCI EHCI controller ids here */
@@ -20,7 +53,6 @@ static struct pci_device_id ehci_pci_ids[] = { {0x12D8, 0x400F}, /* Pericom */ {0, 0} }; -#else #endif /*
@@ -31,9 +63,6 @@ int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **ret_hccr, struct ehci_hcor **ret_hcor) { pci_dev_t pdev; -uint32_t cmd; -struct ehci_hccr *hccr; -struct ehci_hcor *hcor;#ifdef CONFIG_PCI_EHCI_DEVICE pdev =pci_find_devices (ehci_pci_ids,CONFIG_PCI_EHCI_DEVICE );
@@ -44,23 +73,8 @@ int ehci_hcd_init(int index, enum usb_init_type init,printf ("EHCI host controller not found\n" );return -1 ; } +ehci_pci_common_init (pdev, ret_hccr, ret_hcor); - hccr = (struct ehci_hccr *)pci_map_bar (pdev, -PCI_BASE_ADDRESS_0 ,PCI_REGION_MEM ); - hcor = (struct ehci_hcor *)((uint32_t ) hccr + -HC_LENGTH (ehci_readl (&hccr->cr_capbase))); - -debug ("EHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n" , - (uint32_t )hccr, (uint32_t )hcor, - (uint32_t )HC_LENGTH (ehci_readl (&hccr->cr_capbase))); - - *ret_hccr = hccr; - *ret_hcor = hcor; - -/* enable busmaster */ -pci_read_config_dword (pdev,PCI_COMMAND , &cmd); - cmd |=PCI_COMMAND_MASTER ; -pci_write_config_dword (pdev,PCI_COMMAND , cmd);return 0 ; }
@@ -72,3 +86,46 @@ int ehci_hcd_stop(int index) {return 0 ; } +#endif /* nCONFIG_DM_USB */ + +#ifdef CONFIG_DM_USB +static int ehci_pci_probe (struct udevice *dev) +{ +struct ehci_hccr *hccr; +struct ehci_hcor *hcor; + +ehci_pci_common_init (pci_get_bdf (dev), &hccr, &hcor); + +return ehci_register (dev, hccr, hcor,NULL ,0 ,USB_INIT_HOST ); +} + +static int ehci_pci_remove (struct udevice *dev) +{ +int ret; + + ret =ehci_deregister (dev); +if (ret) +return ret; + +return 0 ; +} + +U_BOOT_DRIVER (ehci_pci) = { + .name ="ehci_pci" , + .id =UCLASS_USB , + .probe = ehci_pci_probe, + .remove = ehci_pci_remove, + .ops = &ehci_usb_ops, + .platdata_auto_alloc_size =sizeof (struct usb_platdata ), + .priv_auto_alloc_size =sizeof (struct ehci_pci_priv ), + .flags =DM_FLAG_ALLOC_PRIV_DMA , +}; + +static struct pci_device_id ehci_pci_supported[] = { + {PCI_DEVICE_CLASS (PCI_CLASS_SERIAL_USB_EHCI , ~0 ) }, + {}, +}; + +U_BOOT_PCI_DEVICE (ehci_pci, ehci_pci_supported); + +#endif /* CONFIG_DM_USB */
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 14/18 dm: usb: Add driver-model support to ehci-pci
Quoted 5 lines · Simon Glass
Support driver model in this driver. This uses the normal USB driver search mechanism. Any EHCI controllers will be set up as they are found during
usb_init().Signed-off-by Simon Glass <[email protected]>
Best regards,
Marek Vasut
PATCH 14/18 dm: usb: Add driver-model support to ehci-pci
Quoted 11 lines · Marek Vasut
Quoted 5 lines · Simon Glass
Support driver model in this driver. This uses the normal USB driver search mechanism. Any EHCI controllers will be set up as they are found during
usb_init().Signed-off-by Simon Glass <[email protected]>Reviewed-by Marek Vasut <[email protected]>Best regards,
Marek Vasut
Applied to u-boot-dm.
PATCH 15/18 dm: usb: eth: Add driver-model support to the asix driver
In reply to Simon GlassThis USB Ethernet driver is quite widely use. Allow it to work with CONFIG_DM_ETH enabled. Most of the code remains common but there is a new packet receive flow which is handled specially.
---
drivers/usb/eth/asix.c | 237 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 216 insertions(+), 21 deletions(-)
drivers/usb/eth/asix.c +216 -21
@@ -5,11 +5,11 @@*/ #include <common.h> +#include <dm.h> #include <usb.h> +#include <malloc.h> #include <linux/mii.h> #include "usb_ether.h" -#include <malloc.h> -/* ASIX AX8817X based USB 2.0 Ethernet Devices */
@@ -92,14 +92,20 @@#define FLAG_TYPE_AX88772B (1U << 2)#define FLAG_EEPROM_MAC (1U << 3)/* initial mac address in eeprom */ -/* local vars */ -static int curr_eth_dev;/* index for name of next device detected */ /* driver private */ struct asix_private {int flags; +#ifdef CONFIG_DM_ETH +struct ueth_data ueth; +#endif }; +#ifndef CONFIG_DM_ETH +/* local vars */ +static int curr_eth_dev;/* index for name of next device detected */ +#endif +/* * Asix infrastructure commands */
@@ -284,13 +290,12 @@ static int asix_write_gpio(struct ueth_data *dev, u16 value, int sleep)return ret; } -static int asix_write_hwaddr (struct eth_device *eth) +static int asix_write_hwaddr_common (struct ueth_data *dev,uint8_t *enetaddr) { -struct ueth_data *dev = (struct ueth_data *)eth->priv;int ret; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN); -memcpy (buf, eth->enetaddr,ETH_ALEN ); +memcpy (buf, enetaddr,ETH_ALEN ); ret =asix_write_cmd (dev,AX_CMD_WRITE_NODE_ID ,0 ,0 ,ETH_ALEN , buf);if (ret <0 )
@@ -325,12 +330,11 @@ static int mii_nway_restart(struct ueth_data *dev)return r; } -static int asix_read_mac (struct eth_device *eth) +static int asix_read_mac_common (struct ueth_data *dev, +struct asix_private *priv,uint8_t *enetaddr) { -struct ueth_data *dev = (struct ueth_data *)eth->priv; -struct asix_private *priv = (struct asix_private *)dev->dev_priv; -int i; ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buf, ETH_ALEN); +int i;if (priv->flags &FLAG_EEPROM_MAC ) {for (i =0 ; i < (ETH_ALEN >>1 ); i++) {
@@ -339,7 +343,7 @@ static int asix_read_mac(struct eth_device *eth)debug ("Failed to read SROM address 04h.\n" );return -1 ; } -memcpy ((eth->enetaddr + i *2 ), buf,2 ); +memcpy (enetaddr + i *2 , buf,2 ); } }else { if (asix_read_cmd(dev, AX_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, buf)
@@ -347,7 +351,7 @@ static int asix_read_mac(struct eth_device *eth)debug ("Failed to read MAC address.\n" );return -1 ; } -memcpy (eth->enetaddr, buf,ETH_ALEN ); +memcpy (enetaddr, buf,ETH_ALEN ); }return 0 ;
@@ -414,12 +418,8 @@ static int asix_basic_reset(struct ueth_data *dev)return 0 ; } -/* -* Asix callbacks -*/ -static int asix_init (struct eth_device *eth,bd_t *bd) +static int asix_init_common (struct ueth_data *dev) { -struct ueth_data *dev = (struct ueth_data *)eth->priv;int timeout =0 ;#define TIMEOUT_RESOLUTION 50/* ms */ int link_detected;
@@ -452,9 +452,8 @@ out_err:return -1 ; } -static int asix_send (struct eth_device *eth,void *packet,int length) +static int asix_send_common (struct ueth_data *dev,void *packet,int length) { -struct ueth_data *dev = (struct ueth_data *)eth->priv;int err;u32 packet_len;int actual_len;
@@ -481,6 +480,24 @@ static int asix_send(struct eth_device *eth, void *packet, int length)return err; } +#ifndef CONFIG_DM_ETH +/* +* Asix callbacks +*/ +static int asix_init (struct eth_device *eth,bd_t *bd) +{ +struct ueth_data *dev = (struct ueth_data *)eth->priv; + +return asix_init_common (dev); +} + +static int asix_send (struct eth_device *eth,void *packet,int length) +{ +struct ueth_data *dev = (struct ueth_data *)eth->priv; + +return asix_send_common (dev, packet, length); +} +static int asix_recv (struct eth_device *eth) {struct ueth_data *dev = (struct ueth_data *)eth->priv;
@@ -552,6 +569,13 @@ static void asix_halt(struct eth_device *eth)debug ("** %s()\n" , __func__); } +static int asix_write_hwaddr (struct eth_device *eth) +{ +struct ueth_data *dev = (struct ueth_data *)eth->priv; + +return asix_write_hwaddr_common (dev, eth->enetaddr); +} +/* * Asix probing functions */
@@ -694,9 +718,180 @@ int asix_eth_get_info(struct usb_device *dev, struct ueth_data *ss,return 0 ;/* Get the MAC address */ -if (asix_read_mac (eth)) +if (asix_read_mac_common (ss, priv, eth->enetaddr))return 0 ;debug ("MAC %pM\n" , eth->enetaddr);return 1 ; } +#endif + +#ifdef CONFIG_DM_ETH +static int asix_eth_start (struct udevice *dev) +{ +struct asix_private *priv =dev_get_priv (dev); + +return asix_init_common (&priv->ueth); +} + +void asix_eth_stop (struct udevice *dev) +{ +debug ("** %s()\n" , __func__); +} + +int asix_eth_send (struct udevice *dev,void *packet,int length) +{ +struct asix_private *priv =dev_get_priv (dev); + +return asix_send_common (&priv->ueth, packet, length); +} + +int asix_eth_recv (struct udevice *dev,int flags,uchar **packetp) +{ +struct asix_private *priv =dev_get_priv (dev); +struct ueth_data *ueth = &priv->ueth; +uint8_t *ptr; +int ret, len; +u32 packet_len; + + len =usb_ether_get_rx_bytes (ueth, &ptr); +debug ("%s: first try, len=%d\n" , __func__, len); +if (!len) { +if (!(flags Ð_RECV_CHECK_DEVICE )) +return -EAGAIN ; + ret =usb_ether_receive (ueth,AX_RX_URB_SIZE ); +if (ret == -EAGAIN ) +return ret; + + len =usb_ether_get_rx_bytes (ueth, &ptr); +debug ("%s: second try, len=%d\n" , __func__, len); + } + +/* +* 1st 4 bytes contain the length of the actual data as two +* complementary 16-bit words. Extract the length of the data. +*/ +if (len <sizeof (packet_len)) { +debug ("Rx: incomplete packet length\n" ); + goto err; + } +memcpy (&packet_len, ptr,sizeof (packet_len)); +le32_to_cpus (&packet_len); +if (((~packet_len >>16 ) &0x7ff ) != (packet_len &0x7ff )) { +debug ("Rx: malformed packet length: %#x (%#x:%#x)\n" , + packet_len, (~packet_len >>16 ) &0x7ff , + packet_len &0x7ff ); + goto err; + } + packet_len = packet_len &0x7ff ; +if (packet_len > len -sizeof (packet_len)) { +debug ("Rx: too large packet: %d\n" , packet_len); + goto err; + } + + *packetp = ptr +sizeof (packet_len); +return packet_len; + +err: +usb_ether_advance_rxbuf (ueth,-1 ); +return -EINVAL ; +} + +static int asix_free_pkt (struct udevice *dev,uchar *packet,int packet_len) +{ +struct asix_private *priv =dev_get_priv (dev); + +if (packet_len &1 ) + packet_len++; +usb_ether_advance_rxbuf (&priv->ueth,sizeof (u32) + packet_len); + +return 0 ; +} + +int asix_write_hwaddr (struct udevice *dev) +{ +struct eth_pdata *pdata =dev_get_platdata (dev); +struct asix_private *priv =dev_get_priv (dev); + +if (priv->flags &FLAG_TYPE_AX88172 ) +return -ENOSYS ; + +return asix_write_hwaddr_common (&priv->ueth, pdata->enetaddr); +} + +static int asix_eth_probe (struct udevice *dev) +{ +struct eth_pdata *pdata =dev_get_platdata (dev); +struct asix_private *priv =dev_get_priv (dev); +struct ueth_data *ss = &priv->ueth; +int ret; + + priv->flags = dev->driver_data; + ret =usb_ether_register (dev, ss,AX_RX_URB_SIZE ); +if (ret) +return ret; + + ret =asix_basic_reset (ss); +if (ret) + goto err; + +/* Get the MAC address */ + ret =asix_read_mac_common (ss, priv, pdata->enetaddr); +if (ret) + goto err; +debug ("MAC %pM\n" , pdata->enetaddr); + +return 0 ; + +err: +return usb_ether_deregister (ss); +} + +static const struct eth_ops asix_eth_ops = { + .start = asix_eth_start, + .send = asix_eth_send, + .recv = asix_eth_recv, + .free_pkt = asix_free_pkt, + .stop = asix_eth_stop, + .write_hwaddr = asix_write_hwaddr, +}; + +U_BOOT_DRIVER (asix_eth) = { + .name ="asix_eth" , + .id =UCLASS_ETH , + .probe = asix_eth_probe, + .ops = &asix_eth_ops, + .priv_auto_alloc_size =sizeof (struct asix_private ), + .platdata_auto_alloc_size =sizeof (struct eth_pdata ), +}; + +static const struct usb_device_id asix_eth_id_table[] = { +/* Apple USB Ethernet Adapter */ + {USB_DEVICE (0x05ac ,0x1402 ), .driver_info =FLAG_TYPE_AX88772 }, +/* D-Link DUB-E100 H/W Ver B1 */ + {USB_DEVICE (0x07d1 ,0x3c05 ), .driver_info =FLAG_TYPE_AX88772 }, +/* D-Link DUB-E100 H/W Ver C1 */ + {USB_DEVICE (0x2001 ,0x1a02 ), .driver_info =FLAG_TYPE_AX88772 }, +/* Cables-to-Go USB Ethernet Adapter */ + {USB_DEVICE (0x0b95 ,0x772a ), .driver_info =FLAG_TYPE_AX88772 }, +/* Trendnet TU2-ET100 V3.0R */ + {USB_DEVICE (0x0b95 ,0x7720 ), .driver_info =FLAG_TYPE_AX88772 }, +/* SMC */ + {USB_DEVICE (0x0b95 ,0x1720 ), .driver_info =FLAG_TYPE_AX88172 }, +/* MSI - ASIX 88772a */ + {USB_DEVICE (0x0db0 ,0xa877 ), .driver_info =FLAG_TYPE_AX88772 }, +/* Linksys 200M v2.1 */ + {USB_DEVICE (0x13b1 ,0x0018 ), .driver_info =FLAG_TYPE_AX88172 }, +/* 0Q0 cable ethernet */ + {USB_DEVICE (0x1557 ,0x7720 ), .driver_info =FLAG_TYPE_AX88772 }, +/* DLink DUB-E100 H/W Ver B1 Alternate */ + {USB_DEVICE (0x2001 ,0x3c05 ), .driver_info =FLAG_TYPE_AX88772 }, +/* ASIX 88772B */ + {USB_DEVICE (0x0b95 ,0x772b ), + .driver_info =FLAG_TYPE_AX88772B |FLAG_EEPROM_MAC }, + {USB_DEVICE (0x0b95 ,0x7e2b ), .driver_info =FLAG_TYPE_AX88772B }, + { }/* Terminating entry */ +}; + +U_BOOT_USB_DEVICE (asix_eth, asix_eth_id_table); +#endif
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 15/18 dm: usb: eth: Add driver-model support to the asix driver
Quoted 9 lines · Simon Glass
This USB Ethernet driver is quite widely use. Allow it to work with
CONFIG_DM_ETHenabled. Most of the code remains common but there is a new packet receive flow which is handled specially.Signed-off-by Simon Glass <[email protected]>---
drivers/usb/eth/asix.c | 237 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 216 insertions(+), 21 deletions(-)
Applied to u-boot-dm.
PATCH 16/18 net: Allow drivers to return -ENOSYS with the write_hwaddr() method
In reply to Simon GlassSome drivers may want to implement this method for some of their devices but not for others. So it is not possible to just leave the operation out of the table. Drivers could get around this by masquerading as two separate drivers but that seems unpleasant.
Allow the driver to return an error when it does not want to process the write_hwaddr() method.
---
include/net.h | 4 +++- net/eth.c | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
include/net.h +3 -1
@@ -119,7 +119,9 @@ enum eth_recv_flags {* mcast: Join or leave a multicast group (for TFTP) - optional * write_hwaddr: Write a MAC address to the hardware (used to pass it to Linux * on some platforms like ARM). This function expects the -* eth_pdata::enetaddr field to be populated - optional +* eth_pdata::enetaddr field to be populated. The method can +* return -ENOSYS to indicate that this is not implemented for +this hardware - optional. * read_rom_hwaddr: Some devices have a backup of the MAC address stored in a * ROM on the board. This is how the driver should expose it * to the network stack. This function should fill in the
net/eth.c +6 -0
@@ -287,7 +287,13 @@ static int eth_write_hwaddr(struct udevice *dev)return -EINVAL ; } +/* +* Drivers are allowed to decide not to implement this at +* run-time. E.g. Some devices may use it and some may not. +*/ ret =eth_get_ops (dev)->write_hwaddr (dev); +if (ret == -ENOSYS ) + ret =0 ;if (ret)printf ("\nWarning: %s failed to set MAC address\n" , dev->name);
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 16/18 net: Allow drivers to return -ENOSYS with the write_hwaddr() method
Quoted 8 lines · Simon Glass
Some drivers may want to implement this method for some of their devices but not for others. So it is not possible to just leave the operation out of the table. Drivers could get around this by masquerading as two separate drivers but that seems unpleasant.
Allow the driver to return an error when it does not want to process the
write_hwaddr()method.
Quoted 6 lines
Signed-off-by Simon Glass <[email protected]>---
include/net.h | 4 +++- net/eth.c | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-)
Applied to u-boot-dm.
PATCH 17/18 x86: Convert minnowmax to use CONFIG_DM_NET
In reply to Simon GlassMove to driver model for networking on minnowmax.
---
board/intel/minnowmax/minnowmax.c | 6 ------ configs/minnowmax_defconfig | 1 + 2 files changed, 1 insertion(+), 6 deletions(-)
board/intel/minnowmax/minnowmax.c +0 -6
@@ -8,7 +8,6 @@#include <asm/gpio.h> #include <asm/ibmpc.h> #include <asm/pnp_def.h> -#include <netdev.h> #include <smsc_lpc47m.h> #define SERIAL_DEV PNP_DEV(0x2e, 4)
@@ -32,8 +31,3 @@ void setup_pch_gpios(u16 gpiobase, const struct pch_gpio_map *gpio) {return ; } - -int board_eth_init (bd_t *bis) -{ -return pci_eth_init (bis); -}
configs/minnowmax_defconfig +1 -0
@@ -13,3 +13,4 @@ CONFIG_CMD_NET=y CONFIG_OF_CONTROL=y CONFIG_CPU=y CONFIG_DM_PCI=y +CONFIG_DM_ETH=y
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 17/18 x86: Convert minnowmax to use CONFIG_DM_NET
Quoted 35 lines · Simon Glass
Move to driver model for networking on minnowmax.
Signed-off-by Simon Glass <[email protected]>---
board/intel/minnowmax/minnowmax.c | 6 ------ configs/minnowmax_defconfig | 1 + 2 files changed, 1 insertion(+), 6 deletions(-)board/intel/minnowmax/minnowmax.c +0
-6@@ -8,7 +8,6 @@#include <asm/gpio.h> #include <asm/ibmpc.h> #include <asm/pnp_def.h> -#include <netdev.h> #include <smsc_lpc47m.h> #define SERIAL_DEV PNP_DEV(0x2e, 4)@@ -32,8 +31,3 @@ void setup_pch_gpios(u16 gpiobase, const struct pch_gpio_map *gpio) {return ; } - -int board_eth_init (bd_t *bis) -{ -return pci_eth_init (bis); -}configs/minnowmax_defconfig +0
-0
configs/minnowmax_defconfig CONFIG_CMD_NET=y
Quoted 5 lines
configs/minnowmax_defconfig +1
-1@@ -13,3 +13,4 @@ CONFIG_CMD_NET=y CONFIG_OF_CONTROL=y CONFIG_CPU=y CONFIG_DM_PCI=y +CONFIG_DM_ETH=y --
PATCH 18/18 x86: Convert minnowmax to use CONFIG_DM_USB
In reply to Simon GlassMove to driver model for USB on minnowmax.
---
configs/minnowmax_defconfig | 2 ++ 1 file changed, 2 insertions(+)
configs/minnowmax_defconfig +2 -0
@@ -14,3 +14,5 @@ CONFIG_OF_CONTROL=y CONFIG_CPU=y CONFIG_DM_PCI=y CONFIG_DM_ETH=y +CONFIG_DM_USB=y +CONFIG_USB=y
Signature · 1 line
2.4.3.573.g4eafbef
PATCH 18/18 x86: Convert minnowmax to use CONFIG_DM_USB
Quoted 12 lines · Simon Glass
Move to driver model for USB on minnowmax.
Signed-off-by Simon Glass <[email protected]>---
configs/minnowmax_defconfig | 2 ++ 1 file changed, 2 insertions(+)configs/minnowmax_defconfig +0
-0
configs/minnowmax_defconfig CONFIG_OF_CONTROL=y
Quoted 6 lines
configs/minnowmax_defconfig +2
-1@@ -14,3 +14,5 @@ CONFIG_OF_CONTROL=y CONFIG_CPU=y CONFIG_DM_PCI=y CONFIG_DM_ETH=y +CONFIG_DM_USB=y +CONFIG_USB=y --