iSCSI command execution
-------------------
target_submit_cmd
target_submit_cmd_map_sgls
target_setup_cmd_from_cdb
transport->parse_cdb(sbc_parse_cdb)
sbc_execute_rw
cmd->execute_rw // se_cmd.execute_rw points to sbc_ops->execute_rw
// destination to file
fd_sbc_ops.execute_rw(fd_execute_rw)
fd_do_rw
vfs_readv
vfs_writev
// destination to block device
iblock_sbc_ops.execute_rw(iblock_execute_rw)
// block device read write
iblock_submit_bios
block_lba = (cmd->t_task_lba << 3);
submit_bio
iSCSI communication
-------------------
iscsit_do_tx_data
kernel_sendmsg
iscsit_do_rx_data
kernel_recvmsg
iscsit_accept_np
kernel_accept
iscsit_setup_np
kernel_bind
iSCSI Authentication
-------------------
__iscsi_target_login_thread
iscsi_target_start_negotiation
iscsi_target_do_login
iscsi_target_handle_csg_zero
iscsi_target_do_authentication
iscsi_handle_authentication
2014/09/24
Flash in Linux
NAND & Driver
struct nand_chip {
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw);
}
nand_write
nand_do_write_ops
chip->write_page ( nand_write_page )
ecc->write_page ( nand_write_page_hwecc )
chip->write_buf ( s3c2410_nand_write_buf )
chip->cmdfunc( nand_command )
chip->cmd_ctrl( s3c2410_nand_hwcontrol )
nand_read
nand_do_read_ops
chip->cmdfunc ( nand_command )
chip->cmd_ctrl( s3c2410_nand_hwcontrol )
ecc->read_page_raw ( nand_read_page_raw )
chip->read_buf ( s3c2410_nand_read_buf )
MTD Layer
mtd_read
mtd->_read ( nand_read )
mtd_write
mtd->_write ( nand_write )
UBI Layer
ubi_io_write
mtd_write
ubi_io_read
mtd_read
ubi_attach
scan_fast
scan_peb
scan_all
scan_peb
ubi_io_read_ec_hdr ( check if the header is ok or not )
ubi_add_to_av
add_volume
p = &av->root.rb_node;
rb_link_node(&aeb->u.rb, parent, p);
rb_insert_color(&aeb->u.rb, &av->root);
ubi_attach_mtd_dev
io_init
ubi->peb_size = ubi->mtd->erasesize;
ubi_vid_hdr's lnum holds the logical block number
ubi_ainf_peb, attach information about a physical eraseblock, lnum
ubi_eba_init
vol->eba_tbl = kmalloc
av = ubi_find_av(ai, idx2vol_id(ubi, i));
vol->eba_tbl[aeb->lnum] = aeb->pnum;
Wear-Leveling is in the drivers\mtd\ubi\wl.c
UBI FS
UBIFS to UBI
ubifs_leb_read
ubi_read
ubi_leb_read
ubifs_leb_write
ubi_leb_write
UBIFS's VFS mount point
fs\ubifs\file.c
fs\ubifs\dir.c
fs\ubifs\super.c
struct nand_chip {
int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
uint32_t offset, int data_len, const uint8_t *buf,
int oob_required, int page, int cached, int raw);
}
nand_write
nand_do_write_ops
chip->write_page ( nand_write_page )
ecc->write_page ( nand_write_page_hwecc )
chip->write_buf ( s3c2410_nand_write_buf )
chip->cmdfunc( nand_command )
chip->cmd_ctrl( s3c2410_nand_hwcontrol )
nand_read
nand_do_read_ops
chip->cmdfunc ( nand_command )
chip->cmd_ctrl( s3c2410_nand_hwcontrol )
ecc->read_page_raw ( nand_read_page_raw )
chip->read_buf ( s3c2410_nand_read_buf )
MTD Layer
mtd_read
mtd->_read ( nand_read )
mtd_write
mtd->_write ( nand_write )
UBI Layer
ubi_io_write
mtd_write
ubi_io_read
mtd_read
ubi_attach
scan_fast
scan_peb
scan_all
scan_peb
ubi_io_read_ec_hdr ( check if the header is ok or not )
ubi_add_to_av
add_volume
p = &av->root.rb_node;
rb_link_node(&aeb->u.rb, parent, p);
rb_insert_color(&aeb->u.rb, &av->root);
ubi_attach_mtd_dev
io_init
ubi->peb_size = ubi->mtd->erasesize;
ubi_vid_hdr's lnum holds the logical block number
ubi_ainf_peb, attach information about a physical eraseblock, lnum
ubi_eba_init
vol->eba_tbl = kmalloc
av = ubi_find_av(ai, idx2vol_id(ubi, i));
vol->eba_tbl[aeb->lnum] = aeb->pnum;
Wear-Leveling is in the drivers\mtd\ubi\wl.c
UBI FS
UBIFS to UBI
ubifs_leb_read
ubi_read
ubi_leb_read
ubifs_leb_write
ubi_leb_write
UBIFS's VFS mount point
fs\ubifs\file.c
fs\ubifs\dir.c
fs\ubifs\super.c
2014/09/23
PCI MSI Setup
The Root Complex(RC) controller receives the MSI messages send from PCI device, then RC raise an interrupt to CPU.
During the startup, software tells PCI device the address to where MSI message should be written. The address is mapped to RC controller IO space.
An example implementation:
http://lxr.free-electrons.com/source/arch/arm/mach-iop13xx/msi.c
The call stack:
__write_msi_msg
write_msi_msg
arch_setup_msi_irq
in arch_setup_msi_irq(), the address (to where MSI message is written) is defined as below.
msg.address_hi = 0x0;
msg.address_lo = IOP13XX_MU_MIMR_PCI;
in __write_msi_msg(), the address is actually written to device configuration register (message address register).
http://lxr.free-electrons.com/source/drivers/pci/msi.c#L327
During the startup, software tells PCI device the address to where MSI message should be written. The address is mapped to RC controller IO space.
An example implementation:
http://lxr.free-electrons.com/source/arch/arm/mach-iop13xx/msi.c
The call stack:
__write_msi_msg
write_msi_msg
arch_setup_msi_irq
in arch_setup_msi_irq(), the address (to where MSI message is written) is defined as below.
msg.address_hi = 0x0;
msg.address_lo = IOP13XX_MU_MIMR_PCI;
in __write_msi_msg(), the address is actually written to device configuration register (message address register).
http://lxr.free-electrons.com/source/drivers/pci/msi.c#L327
2014/09/16
Linux Timer Interface
/* Initialize a simple mmio based clocksource */
clocksource_mmio_init
/* set up the handler of timer interrupt ,
In Irq handler, clock_event_device.event_handler will be called.
event_handler: Assigned by the framework to be called by the low level handler of the event source
*/
setup_irq
/* Configure and register a clock event device */
clockevents_config_and_register
clocksource_mmio_init
/* set up the handler of timer interrupt ,
In Irq handler, clock_event_device.event_handler will be called.
event_handler: Assigned by the framework to be called by the low level handler of the event source
*/
setup_irq
/* Configure and register a clock event device */
clockevents_config_and_register
2014/09/11
PCI BAR Assignment
Question:
How PCI BAR is assigned in Linux?
Answer:
Find free space from PCI bus resource in __find_resource, in which resource start and end are allocated ( from the bus IO memory region? )
__pci_assign_resource
pci_bus_alloc_resource
pci_bus_alloc_from_region
allocate_resource
reallocate_resource
__find_resource
In below function, parameter resno is the BAR number.
Reference:
How PCI BAR is assigned in Linux?
Answer:
Find free space from PCI bus resource in __find_resource, in which resource start and end are allocated ( from the bus IO memory region? )
__pci_assign_resource
pci_bus_alloc_resource
pci_bus_alloc_from_region
allocate_resource
reallocate_resource
__find_resource
In below function, parameter resno is the BAR number.
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev, int resno, resource_size_t size, resource_size_t align)
PCI BAR address points device IO. The value of the BAR address is just mapped by OS, not in range of the host physical memory.
To update the BAR to PCI device.
pci_assign_resource // from the res->start ...
pci_update_resource
pcibios_resource_to_bus(dev->bus, ®ion, res);
region->start = res->start - offset;
new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
reg = pci_resource_bar(dev, resno, &type);
pci_write_config_dword(dev, reg, new);
Reference:
http://www.linux-mips.org/wiki/PCI_Subsystem
http://wiki.osdev.org/PCI
2014/09/09
Linux Interrupt on ARM
Question:
How interrupt information get initialized?
Answers:
Usually, in place like arch/arm/mach-xxx/some_file.c, resource of tyep IORESOURCE_IRQ is defined and get registered by calling platform_device_register(struct platform_device).
platform_device.name is used to map device and device driver.
Device driver registration by usually happens when device module is loaded, by calling platform_driver_register(struct platform_driver).
platform_driver.driver.name is used map the device and device driver.
Question:
How driver register interrupt handler?
Answer:
In implementation of function platform_driver.probe(),
irq = platform_get_irq(plat_dev, num) // get an IRQ for a device
request_irq(irq, my_driver_irq_handler, IRQF_TRIGGER_RISING, ... )
Then my_driver_irq_handler() will be called when irq with index "num" is raised.
Question:
ARM CPU has only one IRQ input pin, how could it find out which peripheral raised the interrupt?
How driver interrupt handler get called?
Answer:
The Interrupt could be handled in two ways, call stack below:
1. CONFIG_MULTI_IRQ_HANDLER on
/* Macro in entry-armV.S */
irq_handler
/* This is a function pointer set by set_handle_irq, usually it got set during platform initialization, ex, like in function s3c2410_init_irq(), the pointer points to s3c24xx_handle_irq().
The pointer could also be set in setup_arch(), /arch/arm/kernel/setup.c, as mdesc->handle_irq.
mdesc->handle_irq is initialized in macro MACHINE_START, MACHINE_END,
mdesc->handle_irq could be set as gic_handle_irq(). */
handle_arch_irq
/* Here finds the actually irq number!!! */
s3c24xx_handle_irq
handle_IRQ
/* the kernel irq API, which will invoke actually irq handler. */
generic_handle_irq
2. CONFIG_MULTI_IRQ_HANDLER off
/* Macro in entry-armV.S */
irq_handler
/* get_irqnr_and_base() is called, which is a platform specific macro to query irq controller to find out which irq line is raised. */
arch_irq_handler_default
asm_do_IRQ
handle_IRQ
/* the kernel irq API, which will invoke actually irq handler. */
generic_handle_irq
Question:
When ARM's GIC ( General Interrupt Controller) hardware is used, how IRQ number is retrieved?
Answer:
In file arch/arm/common/gic.c, function gic_handle_irq() reads the interrupt controller's CPU interface register ICCIAR ( interrupt acknowledge register ) to get the IRQ number. The register has 0x08 offset relative to "CPU interface base address".
Code:
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
Reference:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0048b/index.html
Reference:
http://lxr.free-electrons.com/source/Documentation/blockdev/mflash.txt
http://pankaj-techstuff.blogspot.jp/2007/11/story-interrupt-handling-in-linux-2611.html
http://hi.baidu.com/sun_yfs/blog/item/e2531ecbf2cde989c9176806.html
http://lxr.linux.no/#linux+v2.6.32.59/drivers/video/s3c2410fb.c
http://lxr.linux.no/#linux+v2.6.32.59/arch/arm/plat-s3c24xx/irq.c
http://code.metager.de/source/xref/denx/u-boot/doc/README.SPL
http://code.metager.de/source/xref/denx/u-boot/doc/README.arm-relocation
How interrupt information get initialized?
Answers:
Usually, in place like arch/arm/mach-xxx/some_file.c, resource of tyep IORESOURCE_IRQ is defined and get registered by calling platform_device_register(struct platform_device).
platform_device.name is used to map device and device driver.
Device driver registration by usually happens when device module is loaded, by calling platform_driver_register(struct platform_driver).
platform_driver.driver.name is used map the device and device driver.
Question:
How driver register interrupt handler?
Answer:
In implementation of function platform_driver.probe(),
irq = platform_get_irq(plat_dev, num) // get an IRQ for a device
request_irq(irq, my_driver_irq_handler, IRQF_TRIGGER_RISING, ... )
Then my_driver_irq_handler() will be called when irq with index "num" is raised.
Question:
ARM CPU has only one IRQ input pin, how could it find out which peripheral raised the interrupt?
How driver interrupt handler get called?
Answer:
The Interrupt could be handled in two ways, call stack below:
1. CONFIG_MULTI_IRQ_HANDLER on
/* Macro in entry-armV.S */
irq_handler
/* This is a function pointer set by set_handle_irq, usually it got set during platform initialization, ex, like in function s3c2410_init_irq(), the pointer points to s3c24xx_handle_irq().
The pointer could also be set in setup_arch(), /arch/arm/kernel/setup.c, as mdesc->handle_irq.
mdesc->handle_irq is initialized in macro MACHINE_START, MACHINE_END,
mdesc->handle_irq could be set as gic_handle_irq(). */
handle_arch_irq
/* Here finds the actually irq number!!! */
s3c24xx_handle_irq
handle_IRQ
/* the kernel irq API, which will invoke actually irq handler. */
generic_handle_irq
2. CONFIG_MULTI_IRQ_HANDLER off
/* Macro in entry-armV.S */
irq_handler
/* get_irqnr_and_base() is called, which is a platform specific macro to query irq controller to find out which irq line is raised. */
arch_irq_handler_default
asm_do_IRQ
handle_IRQ
/* the kernel irq API, which will invoke actually irq handler. */
generic_handle_irq
Question:
When ARM's GIC ( General Interrupt Controller) hardware is used, how IRQ number is retrieved?
Answer:
In file arch/arm/common/gic.c, function gic_handle_irq() reads the interrupt controller's CPU interface register ICCIAR ( interrupt acknowledge register ) to get the IRQ number. The register has 0x08 offset relative to "CPU interface base address".
Code:
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
Reference:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0048b/index.html
Reference:
http://lxr.free-electrons.com/source/Documentation/blockdev/mflash.txt
http://pankaj-techstuff.blogspot.jp/2007/11/story-interrupt-handling-in-linux-2611.html
http://hi.baidu.com/sun_yfs/blog/item/e2531ecbf2cde989c9176806.html
http://lxr.linux.no/#linux+v2.6.32.59/drivers/video/s3c2410fb.c
http://lxr.linux.no/#linux+v2.6.32.59/arch/arm/plat-s3c24xx/irq.c
http://code.metager.de/source/xref/denx/u-boot/doc/README.SPL
http://code.metager.de/source/xref/denx/u-boot/doc/README.arm-relocation
Subscribe to:
Posts (Atom)
Post Code on Blogger
Simplest way to post code to blogger for me: <pre style="background: #f0f0f0; border: 1px dashed #CCCCCC; color: black;overflow-x:...
-
Explain There is not interrupt PIN for PCIe interrupt. When device wants to raise an interrupt, an interrupt message is sent to host via ...
-
Configure Space Addressing One of the major improvements the PCI Local Bus had over other I/O architectures was its configuration mechanism...
-
What is LMA and VMA Every loadable or allocatable output section has two addresses. The first is the VMA, or virtual memory address. This ...