Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

XHci-PCI driver design

2025-01-21 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/03 Report--

XHci-PCI driver design

Although the Linux kernel has a body built in C language, it emits an object-oriented temperament, and the object of this is struct. When faced with a kernel module, we must first find out the key struct and the relationship between them, in order to find out the skeleton context of the code.

At the beginning of the figure, this is the relationship between the structures at the end of the analysis below:

Important configurations:

XHCI is the host controller specification of USB 3.x. First of all, go to the drivers/usb/host directory and browse. In fact, you can know from the file name that the one most closely related to xHCI must be xhci.c. Just to be on the safe side, take a look at KConfig:

Config USB_XHCI_HCD

Tristate "xHCI HCD (USB 3.0) support"

-help

TheeXtensible Host Controller Interface (xHCI) is standard forUSB 3.0

"SuperSpeed" host controller hardware.

Tocompile this driver as a module, choose M here: the

Module will be called xhci-hcd.

IfUSB_XHCI_HCD

Config USB_XHCI_PCI

Tristate

Depends on PCI

Defaulty

Config USB_XHCI_PLATFORM

Tristate

Config USB_XHCI_MVEBU

Tristate "xHCI support forMarvell Armada 375amp 38x"

Select USB_XHCI_PLATFORM

Depends on ARCH_MVEBU | | COMPILE_TEST

-help

Say'Y'to enable the support for the xHCI host controller

Found in Marvell Armada 375/38x ARM SOCs.

Config USB_XHCI_RCAR

Tristate "xHCI support forRenesas R-Car SoCs"

Select USB_XHCI_PLATFORM

Depends on ARCH_SHMOBILE | | COMPILE_TEST

-help

Say'Y'to enable the support for the xHCI host controller

Found in Renesas R-Car ARM SoCs.

Endif # USB_XHCI_HCD

The main configuration item is called USB_XHCI_HCD, as well as USB_XHCI_PCI and USB_XHCI_PLATFORM. Let's take a look at Makefile and directly search for XHCI-related content:

Xhci-hcd-y: = xhci.oxhci-mem.o

Xhci-hcd-y + = xhci-ring.o xhci-hub.oxhci-dbg.o

Xhci-hcd-y + = xhci-trace.o

Xhci-plat-hcd-y: = xhci-plat.o

Ifneq ($(CONFIG_USB_XHCI_MVEBU),)

Xhci-plat-hcd-y + = xhci-mvebu.o

Endif

Ifneq ($(CONFIG_USB_XHCI_RCAR),)

Xhci-plat-hcd-y + = xhci-rcar.o

Endif

Obj-$ (CONFIG_USB_XHCI_PCI) + = xhci-pci.o

Obj-$ (CONFIG_USB_XHCI_PLATFORM) + = xhci-plat-hcd.o

Obj-$ (CONFIG_USB_XHCI_HCD) + = xhci-hcd.o

USB_XHCI_PCI, as its name implies, is the "interface" between the xHCI driver and the PCI bus driver (kernel developers call this "interface" glue). Most of the USB controllers are PCI devices. If the controller is connected to the PCI bus, the device is naturally discovered by the PCI driver first, and then it can be handed over to the xHCI driver for processing. So in fact, the xhci-pci module code as glue starts working before the xhci-hcd module code, so the key initialization process is placed in xhci-pci.

Now let's get to the point:

With xHCI-related code, it's easy to find several seemingly important struct types: usb_hcd, xhci_hcd, and hc_driver, as well as several global variables xhci_pci_driver, xhci_hc_driver, and xhci_pci_hc_driver, plus the PCI bus-related types pci_dev and pci_driver.

The xhci-pci module starts to execute the xhci_pci_init function

Staticint__init xhci_pci_init (void)

{

Xhci_init_driver (& xhci_pci_hc_driver, xhci_pci_setup)

# ifdef CONFIG_PM

Xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend

Xhci_pci_hc_driver.pci_resume = xhci_pci_resume

# endif

Returnpci_register_driver & xhci_pci_driver)

}

Xhci_pci_init calls xhci_init_driver to initialize the xhci_pci_hc_driver variable, and its main function is to assign the value of the global variable xhci_hc_driver to another global variable xhci_pci_hc_driver. Both are struct hc_driver types. Xhci_pci_hc_driver is defined in xhci-pci.c and is the xHCI driver that really works, but it does not initialize any members at the time of definition:

Void xhci_init_driver (struct hc_driver * drv, int (* setup_fn) (struct usb_hcd *))

{

BUG_ON (! setup_fn)

* drv= xhci_hc_driver

Drv- > reset= setup_fn

}

Staticstructhc_driver _ _ read_mostly xhci_pci_hc_driver

While xhci_hc_driver is defined in xhci.c, it does all the dirty work:

Staticconststruct hc_driver xhci_hc_driver = {

.description = "xhci-hcd"

.product _ desc = "xHCI Host Controller"

.hcd _ priv_size= sizeof (structxhci_hcd *)

/ *

* generic hardware linkage

, /

.irq = xhci_irq

.flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED

/ *

* basic lifecycle operations

, /

.reset = NULL, / * set in xhci_init_driver () * /

.start = xhci_run

.stop = xhci_stop

.shutdown = xhci_shutdown

/ *

* managing iUnix o requests and associated device resources

, /

.urb _ enqueue = xhci_urb_enqueue

.urb _ dequeue = xhci_urb_dequeue

.alloc _ dev = xhci_alloc_dev

.free _ dev = xhci_free_dev

.alloc _ streams = xhci_alloc_streams

.free _ streams = xhci_free_streams

.add _ endpoint = xhci_add_endpoint

.drop _ endpoint= xhci_drop_endpoint

.clients _ reset = xhci_endpoint_reset

.check _ bandwidth = xhci_check_bandwidth

.reset _ bandwidth = xhci_reset_bandwidth

.address _ device = xhci_address_device

.enable _ device = xhci_enable_device

.update _ hub_device = xhci_update_hub_device

.reset _ device = xhci_discover_or_reset_device

/ *

* scheduling support

, /

.get _ frame_number = xhci_get_frame

/ *

* root hub support

, /

.hub _ control = xhci_hub_control

.hub _ status_data = xhci_hub_status_data

.bus _ suspend = xhci_bus_suspend

.bus _ resume = xhci_bus_resume

/ *

* call back when device connected and addressed

, /

.update _ device = xhci_update_device

.set _ usb2_hw_lpm = xhci_set_usb2_hardware_lpm

.enable _ usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout

.disable _ usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout

.find _ raw_port_number = xhci_find_raw_port_number

}

When the xhci_init_driver function assigns the value of xhci_hc_driver to xhci_pci_hc_driver, the former steps off the stage.

Xhci_pci_driver is called pcidriver glue by professionals, which belongs to a new type of PCI driver module.

Xhci_pci_init calls pci_register_driver to register xhci_pci_driver as the PCI device driver. Statically define and initialize in xhci-pci.c:

/ * pci driver glue; this is a "new style" PCI driver module * /

Staticstructpci_driver xhci_pci_driver = {

.name = (char*) hcd_name

.id _ table = pci_ids

.probe = xhci_pci_probe

.remove = xhci_pci_remove

/ * suspend and resume implemented later * /

.shutdown = usb_hcd_pci_shutdown

# ifdef CONFIG_PM

.driver = {

.pm = & usb_hcd_pci_pm_ops

}

# endif

}

Id_table contains the types of PCI devices supported by the driver, and the PCI bus depends on it to determine whether the driver and the device can be matched. The id_table member here is set to pci_ids, which is also a statically defined global variable:

/ * PCI driver selectionmetadata; PCI hotplugging uses this * /

Staticconststructpci_device_id pci_ids [] = {{

/ * handle any USB 3.0 xHCI controller * /

PCI_DEVICE_CLASS (PCI_CLASS_SERIAL_USB_XHCI, ~ 0)

.driver _ data = (unsignedlong) & xhci_pci_hc_driver

}

{/ * end: all zeroes * /}

}

MODULE_DEVICE_TABLE (pci, pci_ids)

The driver_data member of the only element in pci_ids points to the xhci_pci_hc_driver variable that has just been initialized in xhci_pci_init, which connects xhci_pci_driver as the PCI device driver and xhci_pci_hc_driver as the USB host controller device driver.

Staticintxhci_pci_setup (struct usb_hcd * hcd)

{

Structxhci_hcd * xhci

Structpci_dev * pdev = to_pci_dev (hcd- > self.controller)

Int retval

/ / configuration of uDP720202 chip

Xhci_fwdownload (hcd)

/ / created the xhci_hcd type, a data structure that is very important to xHCI, and completed a lot of initialization work

Retval = xhci_gen_setup (hcd, xhci_pci_quirks)

If (retval)

Return retval

Xhci = hcd_to_xhci (hcd)

If (! usb_hcd_is_primary_hcd (hcd))

Return0

Pci_read_config_byte (pdev, XHCI_SBRN_OFFSET, & xhci- > sbrn)

Xhci_dbg (xhci, "GotSBRN% u\ n", (unsignedint) xhci- > sbrn)

/ * Find any debug ports * /

Retval = xhci_pci_reinit (xhci, pdev)

If (! retval)

Return retval

Kfree (xhci)

Returnretval

}

As can be seen from Figure 3-1 in USB 3.1Spec, the Host of USB 3.x contains two roothub corresponding to two USB buses, one connecting USB 2.0 devices and the other connecting USB 3.x devices.

Xhci_pci_probe calls usb_hcd_pci_probe to create usb_hcd and xhci_hcd. Going back to the original diagram, now all the connections have been completed!

Int usb_hcd_pci_probe (struct pci_dev * dev, conststruct pci_device_id * id)

{

Structhc_driver * driver

Structusb_hcd * hcd

Int retval

Int hcd_irq = 0

If (usb_disabled ())

Return-ENODEV

If (! id)

Return-EINVAL

Driver= (structhc_driver *) id- > driver_data

If (! driver)

Return-EINVAL

If (pci_enable_device (dev))

< 0) return-ENODEV; /* * The xHCI driver has its own irq management * make sure irq setup is not touched for xhciin generic hcd code */ if((driver->

Flags & HCD_MASK)! = HCD_USB3) {

If (! dev- > irq) {

Dev_err (& dev- > dev

"Found HC with no IRQ. Check BIOS/PCI% s setup!\ n"

Pci_name (dev))

Retval=-ENODEV

Gotodisable_pci

}

Hcd_irq= dev- > irq

}

Hcd = usb_create_hcd (driver, & dev- > dev, pci_name (dev))

If (! hcd) {

Retval=-ENOMEM

Gotodisable_pci

}

.

Returnretval

}

Timing diagram of the configuration of the uDP720202 chip:

/ / @ @-- PCI information

# define XHCI_FWFILENAME_720201_202ES20 "renesas/K2011070.mem"

/ / uDp720202 register configuration

# define XHCI_VENDOR_ID_720202 (0x1912)

# define XHCI_DEVICE_ID_720202 (0x0015)

# define XHCI_DEVICE_REV_ES20 (0x02)

/ / @ @-- FM download configuration register

# define PCICNF0F4 0xF4 / / from the chip register manual

/ *

0 = FWdownload enable (1), RW

1 = FWdownload lock (1) or unlock (0), need 0 to perform download, RW (Write Once)

6:4 = Result code, RO-- processing (0), success (1), error (2)

8 = Set Data 0, RW

9 = Set Data 1, RW

16 31 = (used for serial EEPROM read/write. 31 = serial EEPROM present.)

, /

# define PCICNF0F4_FWDOWNLOADENABLE_B (0)

# define PCICNF0F4_FWDOWNLOADLOCK_B (1)

# define PCICNF0F4_SETDATA0_B (8)

# define PCICNF0F4_SETDATA1_B (9)

# define PCICNF0F4_RESULT_B (4)

# define PCICNF0F8 0xF8 / / data page 0

# define PCICNF0FC 0xFC / / data Page 1

The main calling procedure is:

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report