虽然Linux内核拥有C语言构建的身体,但它骨子里散发的是面向对象的气质,这一个个的对象就是struct。面对一个内核模块的时候,首先要找出关键的struct和它们之间的关系,才能摸清代码的骨骼脉络。
大致浏览几眼xHCI相关的代码,很容易发现几个貌似重要的struct类型:usb_hcd
、xhci_hcd
和hc_driver
,还有几个全局变量xhci_pci_driver
、xhci_hc_driver
和xhci_pci_hc_driver
,再加上PCI总线相关的类型pci_dev
和pci_driver
。不要被这些眼花缭乱的名字吓到,今天要做的就是把这些结构之间的关系理顺。下面按照相关代码的执行顺序,看一下这些结构是如何被建立和初始化的。
xhci_pci_init
函数static int __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
return pci_register_driver(&xhci_pci_driver);
}
xhci_pci_init
调用xhci_init_driver
,初始化xhci_pci_hc_driver
变量xhci_init_driver
函数是在xhci.c中定义的,主要作用就是把全局变量xhci_hc_driver
的值一股脑赋给另一个全局变量xhci_pci_hc_driver
。两者都是struct hc_driver
类型,xhci_pci_hc_driver
在xhci-pci.c中定义,是真正起作用的xHCI驱动,但它在定义的时候没有进行任何成员的初始化:
static struct hc_driver __read_mostly xhci_pci_hc_driver;
而xhci_hc_driver在xhci.c中定义,它包揽了所有的脏活累活:
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
.hcd_priv_size = sizeof(struct xhci_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 i/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,
.endpoint_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,
};
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;
}
xhci_init_driver
函数将xhci_hc_driver
的值赋给xhci_pci_hc_driver
后,前者也就退下了舞台。不信,你看:
(free-electrons是个好网站)
xhci_pci_init
调用pci_register_driver
,将xhci_pci_driver
注册为PCI设备驱动xhci_pci_driver
是xHCI控制器作为PCI设备对应的驱动,符合PCI设备驱动的标准类型struct pci_driver
,在xhci-pci.c中静态定义并初始化:
/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_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
,一个是probe
。id_table
包含了驱动支持的PCI设备类型,PCI总线就是靠它判断驱动和设备能否配对。这里的id_table
成员设置为pci_ids
,它也是静态定义的全局变量:
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids[] = { {
/* handle any USB 3.0 xHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
.driver_data = (unsigned long) &xhci_pci_hc_driver,
},
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);
注意pci_ids
中唯一一个元素的driver_data
成员指向刚才在xhci_pci_init
中完成初始化的xhci_pci_hc_driver
变量,这就将作为PCI设备驱动的xhci_pci_driver
和作为USB主机控制器设备驱动xhci_pci_hc_driver
联系了起来。本文最开始的图中右半部分画出了它们的关系。
当pci_register_driver
调用完成后,xhci_pci_driver
就被加入了PCI总线的驱动列表,当总线检测到与之匹配的设备,即xHCI控制器的时候,会调用驱动的probe成员函数,而xhci_pci_driver.probe
在初始化时被设置为xhci_pci_probe
函数,因此接下来就顺藤摸瓜考察它。
xhci_pci_probe
函数这个函数也定义在xhci-pci.c中,比较长(所以加了行号),先贴前半部分:
217 static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
218 {
219 int retval;
220 struct xhci_hcd *xhci;
221 struct hc_driver *driver;
222 struct usb_hcd *hcd;
223
224 driver = (struct hc_driver *)id->driver_data;
225
226 /* Prevent runtime suspending between USB-2 and USB-3 initialization */
227 pm_runtime_get_noresume(&dev->dev);
228
229 /* Register the USB 2.0 roothub.
230 * FIXME: USB core must know to register the USB 2.0 roothub first.
231 * This is sort of silly, because we could just set the HCD driver flags
232 * to say USB 2.0, but I'm not sure what the implications would be in
233 * the other parts of the HCD code.
234 */
235 retval = usb_hcd_pci_probe(dev, id);
236
237 if (retval)
238 goto put_runtime_pm;
...
注意函数的两个参数,由于是被PCI总线驱动调用的,因此一个是pci_dev
结构,一个是pci_device_id
结构。224行,程序从pci_device_id
结构中取出了driver_data
成员。刚才说到xHCI的pci_device_id
结构中的driver_data
成员指向xhci_pci_hc_driver
,因此接下来driver
指针都是指向它。
235行,调用usb_hcd_pci_probe
函数。这是USB 1.x和2.0的各种控制器驱动使用的probe函数,为什么此处要用它呢?从USB 3.1 Spec中Figure 3-1可以知道,USB 3.x的Host包含两个roothub,对应两条USB总线,一条连接USB 2.0设备,一条连接USB 3.x设备。在xHCI驱动里,需要为每个roothub建立一个usb_hcd
结构,而2.0 roothub需要首先创建,因此就直接调用usb_hcd_pci_probe
了。
usb_hcd
结构类型的定义位于include/linux/usb/hcd.h:
79 struct usb_hcd {
80
81 /*
82 * housekeeping
83 */
84 struct usb_bus self; /* hcd is-a bus */
85 struct kref kref; /* reference counter */
...
从上面可以看到,每个usb_hcd
中包含一个usb_bus
结构,代表对应的总线。再看下面的代码,每个usb_bus
中又包含device
结构指针指向对应的设备模型。由于这里的两条USB总线在系统中实际属于同一个物理设备(都对应xHCI控制器这个PCI设备里),因此可以想象同一个xHCI控制器对应的两个usb_bus
结构中的device
指针应当指向同一处。
usb_bus
结构类型的定义位于include/linux/usb.h:
319 /*
320 * Allocated per bus (tree of devices) we have:
321 */
322 struct usb_bus {
323 struct device *controller; /* host/master side hardware */
324 int busnum; /* Bus number (in order of reg) */
325 const char *bus_name; /* stable id (PCI slot_name etc) */
...
xhci_pci_probe
调用usb_hcd_pci_probe
,创建usb_hcd
和xhci_hcd
回到正题,考察usb_hcd_pci_probe
函数:
177 int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
178 {
179 struct hc_driver *driver;
180 struct usb_hcd *hcd;
181 int retval;
182 int hcd_irq = 0;
183
184 if (usb_disabled())
185 return -ENODEV;
186
187 if (!id)
188 return -EINVAL;
189 driver = (struct hc_driver *)id->driver_data;
190 if (!driver)
191 return -EINVAL;
192
193 if (pci_enable_device(dev) < 0)
194 return -ENODEV;
195
196 /*
197 * The xHCI driver has its own irq management
198 * make sure irq setup is not touched for xhci in generic hcd code
199 */
200 if ((driver->flags & HCD_MASK) != HCD_USB3) {
201 if (!dev->irq) {
202 dev_err(&dev->dev,
203 "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
204 pci_name(dev));
205 retval = -ENODEV;
206 goto disable_pci;
207 }
208 hcd_irq = dev->irq;
209 }
210
211 hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));
212 if (!hcd) {
213 retval = -ENOMEM;
214 goto disable_pci;
215 }
216
217 hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) &&
218 driver->flags & (HCD_USB11 | HCD_USB3)) ? 1 : 0;
219
220 if (driver->flags & HCD_MEMORY) {
221 /* EHCI, OHCI */
...
237 } else {
238 /* UHCI */
...
257 }
258
259 pci_set_master(dev);
260
261 /* Note: dev_set_drvdata must be called while holding the rwsem */
262 if (dev->class == CL_EHCI) {
263 down_write(&companions_rwsem);
264 dev_set_drvdata(&dev->dev, hcd);
265 for_each_companion(dev, hcd, ehci_pre_add);
266 retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
267 if (retval != 0)
268 dev_set_drvdata(&dev->dev, NULL);
269 for_each_companion(dev, hcd, ehci_post_add);
270 up_write(&companions_rwsem);
271 } else {
272 down_read(&companions_rwsem);
273 dev_set_drvdata(&dev->dev, hcd);
274 retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED);
275 if (retval != 0)
276 dev_set_drvdata(&dev->dev, NULL);
277 else
278 for_each_companion(dev, hcd, non_ehci_add);
279 up_read(&companions_rwsem);
280 }
281
282 if (retval != 0)
283 goto unmap_registers;
284 device_wakeup_enable(hcd->self.controller);
285
286 if (pci_dev_run_wake(dev))
287 pm_runtime_put_noidle(&dev->dev);
288 return retval;
...
为了节约显示器,中间一些与xHCI无关的细节和末尾的错误处理代码就先省略了。这里最关键的,189行中使用和xhci_pci_probe
函数中同样的方法令driver
指针指向了xhci_pci_hc_driver
。211行,调用usb_create_hcd
函数创建usb_hcd
结构。
usb_hcd_pci_probe
调用usb_create_hcd
,进而调用usb_create_shared_hcd
创建usb_hcd
结构2501 struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
2502 struct device *dev, const char *bus_name)
2503 {
2504 return usb_create_shared_hcd(driver, dev, bus_name, NULL);
2505 }
2434 struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
2435 struct device *dev, const char *bus_name,
2436 struct usb_hcd *primary_hcd)
2437 {
2438 struct usb_hcd *hcd;
2439
2440 hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
2441 if (!hcd) {
2442 dev_dbg (dev, "hcd alloc failed\n");
2443 return NULL;
2444 }
2445 if (primary_hcd == NULL) {
2446 hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
2447 GFP_KERNEL);
2448 if (!hcd->bandwidth_mutex) {
2449 kfree(hcd);
2450 dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
2451 return NULL;
2452 }
2453 mutex_init(hcd->bandwidth_mutex);
2454 dev_set_drvdata(dev, hcd);
2455 } else {
2456 mutex_lock(&usb_port_peer_mutex);
2457 hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
2458 hcd->primary_hcd = primary_hcd;
2459 primary_hcd->primary_hcd = primary_hcd;
2460 hcd->shared_hcd = primary_hcd;
2461 primary_hcd->shared_hcd = hcd;
2462 mutex_unlock(&usb_port_peer_mutex);
2463 }
2464
2465 kref_init(&hcd->kref);
2466
2467 usb_bus_init(&hcd->self);
2468 hcd->self.controller = dev;
2469 hcd->self.bus_name = bus_name;
2470 hcd->self.uses_dma = (dev->dma_mask != NULL);
2471
2472 init_timer(&hcd->rh_timer);
2473 hcd->rh_timer.function = rh_timer_func;
2474 hcd->rh_timer.data = (unsigned long) hcd;
2475 #ifdef CONFIG_PM
2476 INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
2477 #endif
2478
2479 hcd->driver = driver;
2480 hcd->speed = driver->flags & HCD_MASK;
2481 hcd->product_desc = (driver->product_desc) ? driver->product_desc :
2482 "USB Host Controller";
2483 return hcd;
2484 }
2440行,创建usb_hcd
类型变量。
2445行,由于usb_create_hcd
调用usb_create_shared_hcd
时primary_hcd
参数为NULL,进入if语句的第一个分支。
2454行,令pci_device
中内嵌的device
结构的driver_data
成员指向刚创建的usb_hcd
结构。
2468行,令usb_hcd
中内嵌的usb_bus
结构的controller
指针指向device
结构。
2479行,令usb_hcd
中的driver
成员指向xhci_pci_hc_driver
。
回到usb_hcd_pci_probe
函数,264/273行又设置了一遍driver_data
,貌似跟上面重复了。
usb_hcd_pci_probe
调用usb_add_hcd
,最终调用xhci_gen_setup
,创建xhci_hcd
结构2625 int usb_add_hcd(struct usb_hcd *hcd,
2626 unsigned int irqnum, unsigned long irqflags)
2627 {
...
2733 /* "reset" is misnamed; its role is now one-time init. the controller
2734 * should already have been reset (and boot firmware kicked off etc).
2735 */
2736 if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
2737 dev_err(hcd->self.controller, "can't setup: %d\n", retval);
2738 goto err_hcd_driver_setup;
2739 }
...
usb_add_hcd
函数很长,最关键的是它调用了xhci_pci_hc_driver
的reset
成员,即xhci_pci_setup
函数,后者又进一步调用xhci_gen_setup
。
187 static int xhci_pci_setup(struct usb_hcd *hcd)
188 {
189 struct xhci_hcd *xhci;
190 struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
191 int retval;
192
193 retval = xhci_gen_setup(hcd, xhci_pci_quirks);
194 if (retval)
195 return retval;
196
197 xhci = hcd_to_xhci(hcd);
198 if (!usb_hcd_is_primary_hcd(hcd))
199 return 0;
200
201 pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
202 xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
203
204 /* Find any debug ports */
205 retval = xhci_pci_reinit(xhci, pdev);
206 if (!retval)
207 return retval;
208
209 kfree(xhci);
210 return retval;
211 }
4819 int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
4820 {
4821 struct xhci_hcd *xhci;
4822 struct device *dev = hcd->self.controller;
4823 int retval;
4824
4825 /* Accept arbitrarily long scatter-gather lists */
4826 hcd->self.sg_tablesize = ~0;
4827
4828 /* support to build packet from discontinuous buffers */
4829 hcd->self.no_sg_constraint = 1;
4830
4831 /* XHCI controllers don't stop the ep queue on short packets :| */
4832 hcd->self.no_stop_on_short = 1;
4833
4834 if (usb_hcd_is_primary_hcd(hcd)) {
4835 xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
4836 if (!xhci)
4837 return -ENOMEM;
4838 *((struct xhci_hcd **) hcd->hcd_priv) = xhci;
4839 xhci->main_hcd = hcd;
4840 /* Mark the first roothub as being USB 2.0.
4841 * The xHCI driver will register the USB 3.0 roothub.
4842 */
4843 hcd->speed = HCD_USB2;
4844 hcd->self.root_hub->speed = USB_SPEED_HIGH;
4845 /*
4846 * USB 2.0 roothub under xHCI has an integrated TT,
4847 * (rate matching hub) as opposed to having an OHCI/UHCI
4848 * companion controller.
4849 */
4850 hcd->has_tt = 1;
4851 } else {
4852 /* xHCI private pointer was set in xhci_pci_probe for the second
4853 * registered roothub.
4854 */
4855 return 0;
4856 }
...
xhci_gen_setup
最大的作用就是创建了对xHCI至关重要的数据结构——xhci_hcd
类型,并完成了大量的初始化工作。今天只关注结构体之间的关系,因此省略了后面初始化的代码。
4835行,创建xhci_hcd
类型变量。
4838行,令usb_hcd
中的hcd_priv
成员指向新创建的xhci_hcd
。
4839行,令xhci_hcd
中的main_hcd
变量指向usb_hcd
。
下面回到xhci_pci_probe
函数。从此处返回的顺序是xhci_gen_setup
->xhci_pci_setup
->usb_add_hcd
->usb_hcd_pci_probe
->xhci_pci_probe
。
xhci_pci_probe
调用usb_create_shared_hcd
创建第二个usb_hcd
结构现在USB 2.0 roothub设置完成,xhci_pci_probe
从240行开始继续执行:
217 static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
218 {
...
235 retval = usb_hcd_pci_probe(dev, id);
236
237 if (retval)
238 goto put_runtime_pm;
239
240 /* USB 2.0 roothub is stored in the PCI device now. */
241 hcd = dev_get_drvdata(&dev->dev);
242 xhci = hcd_to_xhci(hcd);
243 xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev,
244 pci_name(dev), hcd);
245 if (!xhci->shared_hcd) {
246 retval = -ENOMEM;
247 goto dealloc_usb2_hcd;
248 }
...
243行,这次是xhci_pci_probe
亲自调用usb_create_shared_hcd
,创建USB 3.x roothub对应的usb_hcd
。这次由于有了USB 2.0 roothub对应的usb_hcd
作为primary_hcd
,因此usb_create_shared_hcd
函数在其2445行落入第二个分支,一口气设置好了两个usb_hcd
变量的primary_hcd
和shared_hcd
成员:
2434 struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
2435 struct device *dev, const char *bus_name,
2436 struct usb_hcd *primary_hcd)
2437 {
2438 struct usb_hcd *hcd;
2439
2440 hcd = kzalloc(sizeof(*hcd) + driver->hcd_priv_size, GFP_KERNEL);
...
2445 if (primary_hcd == NULL) {
...
2455 } else {
2456 mutex_lock(&usb_port_peer_mutex);
2457 hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
2458 hcd->primary_hcd = primary_hcd;
2459 primary_hcd->primary_hcd = primary_hcd;
2460 hcd->shared_hcd = primary_hcd;
2461 primary_hcd->shared_hcd = hcd;
2462 mutex_unlock(&usb_port_peer_mutex);
2463 }
顺便,也设置了第二个usb_hcd
的driver
成员和self.controller
,跟前面一样。
再次回到xhci_pci_probe
:
217 static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
218 {
...
240 /* USB 2.0 roothub is stored in the PCI device now. */
241 hcd = dev_get_drvdata(&dev->dev);
242 xhci = hcd_to_xhci(hcd);
243 xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev,
244 pci_name(dev), hcd);
245 if (!xhci->shared_hcd) {
246 retval = -ENOMEM;
247 goto dealloc_usb2_hcd;
248 }
249
250 /* Set the xHCI pointer before xhci_pci_setup() (aka hcd_driver.reset)
251 * is called by usb_add_hcd().
252 */
253 *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
254
255 retval = usb_add_hcd(xhci->shared_hcd, dev->irq,
256 IRQF_SHARED);
257 if (retval)
258 goto put_usb3_hcd;
259 /* Roothub already marked as USB 3.0 speed */
260
261 if (!(xhci->quirks & XHCI_BROKEN_STREAMS) &&
262 HCC_MAX_PSA(xhci->hcc_params) >= 4)
263 xhci->shared_hcd->can_do_streams = 1;
264
265 /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
266 pm_runtime_put_noidle(&dev->dev);
267
268 return 0;
...
243行,usb_create_shared_hcd
返回的时候,直接令xhci_hcd
的shared_hcd
成员指向新创建的usb_hcd
。
253行,令新创建的usb_hcd
的hcd_priv
成员指向xhci_hcd
。
回到最初的示意图,现在所有的连接都已经完成!